feat: adding animation for the window border

This commit is contained in:
Lucas Oskorep
2024-11-08 19:54:19 -05:00
parent 91213ed63a
commit 39ddbcd2bc
5 changed files with 175 additions and 36 deletions
+3
View File
@@ -21,6 +21,7 @@ $(NAME).zip: dist/extension.js dist/prefs.js schemas/gschemas.compiled
@cp stylesheet.css dist/ @cp stylesheet.css dist/
@(cd dist && zip ../$(NAME).zip -9r .) @(cd dist && zip ../$(NAME).zip -9r .)
pack: $(NAME).zip pack: $(NAME).zip
install: $(NAME).zip install: $(NAME).zip
@@ -34,3 +35,5 @@ clean:
test: test:
@dbus-run-session -- gnome-shell --nested --wayland @dbus-run-session -- gnome-shell --nested --wayland
install-and-test: install test
+73
View File
@@ -0,0 +1,73 @@
export default class RGBColor {
r: number;
g: number;
b: number;
a: number;
constructor(r: number, g: number, b: number, a: number = 0.8) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
static fromHSL(hsl: HSLColor): RGBColor {
// Normalize HSL values
hsl.h = hsl.h % 360;
hsl.s = Math.max(0, Math.min(1, hsl.s));
hsl.l = Math.max(0, Math.min(1, hsl.l));
hsl.a = Math.max(0, Math.min(1, hsl.a)); // Clamp alpha between 0 and 1
const c = (1 - Math.abs(2 * hsl.l - 1)) * hsl.s;
const x = c * (1 - Math.abs((hsl.h / 60) % 2 - 1));
const m = hsl.l - c / 2;
let r = 0, g = 0, b = 0;
if (hsl.h < 60) {
r = c;
g = x;
b = 0;
} else if (hsl.h < 120) {
r = x;
g = c;
b = 0;
} else if (hsl.h < 180) {
r = 0;
g = c;
b = x;
} else if (hsl.h < 240) {
r = 0;
g = x;
b = c;
} else if (hsl.h < 300) {
r = x;
g = 0;
b = c;
} else {
r = c;
g = 0;
b = x;
}
return new RGBColor(
Math.round((r + m) * 255),
Math.round((g + m) * 255),
Math.round((b + m) * 255),
hsl.a
);
}
}
export class HSLColor {
h: number;
s: number;
l: number;
a: number;
constructor(h: number, s: number, l: number, a: number = .8) {
this.h = h;
this.s = s;
this.l = l;
this.a = a;
}
}
+81 -19
View File
@@ -4,7 +4,9 @@ import St from 'gi://St';
import Meta from 'gi://Meta'; import Meta from 'gi://Meta';
import Shell from 'gi://Shell'; import Shell from 'gi://Shell';
import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { Extension, ExtensionMetadata } from 'resource:///org/gnome/shell/extensions/extension.js'; import {Extension, ExtensionMetadata} from 'resource:///org/gnome/shell/extensions/extension.js';
import Color, {HSLColor} from "./color.js";
import RGBColor from "./color.js";
export default class ActiveBorderExtension extends Extension { export default class ActiveBorderExtension extends Extension {
@@ -13,6 +15,10 @@ export default class ActiveBorderExtension extends Extension {
lastFocusedWindow: Meta.Window | null; lastFocusedWindow: Meta.Window | null;
_focusSignal: number | null; _focusSignal: number | null;
// New variables for color.ts cycling
colorTimeoutId: number | null;
currentColor: HSLColor;
constructor(metadata: ExtensionMetadata) { constructor(metadata: ExtensionMetadata) {
super(metadata); super(metadata);
// Initialize instance variables // Initialize instance variables
@@ -20,25 +26,35 @@ export default class ActiveBorderExtension extends Extension {
this.focusWindowSignals = []; this.focusWindowSignals = [];
this.lastFocusedWindow = null; this.lastFocusedWindow = null;
this._focusSignal = null; this._focusSignal = null;
// Initialize color.ts cycling variables
this.colorTimeoutId = null;
this.currentColor = new HSLColor(0, 1, .5); // Starting hue value
} }
enable() { enable() {
console.log("STARTING PRETTY BORDERS!") console.log("STARTING PRETTY BORDERS!")
// Connect to the focus window signal to track the active window // Connect to the focus window signal to track the active window
this._focusSignal = global.display.connect('notify::focus-window', () => { this._focusSignal = global.display.connect('notify::focus-window', () => {
console.log("Focus Changed")
this._updateBorder(global.display.focus_window); this._updateBorder(global.display.focus_window);
}); });
// Connect to the "showing" signal for when the overview is opened
// let grab_begin = global.display.connect("grab-op-begin", () => {
// console.log("Grab Started")
// })
// let grab_end = global.display.connect("grab-op-end", () => {
// console.log("Grab Ended")
// })
// Set initial border on the current window, if there is one // Set initial border on the current window, if there is one
this._updateBorder(global.display.focus_window); this._updateBorder(global.display.focus_window);
} }
_updateBorder(window: Meta.Window) { _updateBorder(window: Meta.Window) {
console.log("UPDATING THE BORDER") console.log("UPDATING THE BORDER")
// Clear the previous border if there's a last focused window // Clear the previous border
// if (this.lastFocusedWindow) {
// this._clearBorder(this.lastFocusedWindow);
// }
this._clearBorder(); this._clearBorder();
// Set a new border for the currently focused window // Set a new border for the currently focused window
if (window) { if (window) {
@@ -57,18 +73,20 @@ export default class ActiveBorderExtension extends Extension {
// Create a new actor for the border using St.Widget // Create a new actor for the border using St.Widget
this.borderActor = new St.Widget({ this.borderActor = new St.Widget({
name: 'active-window-border', name: 'active-window-border',
style_class: 'active-window-border', // style_class: 'active-window-border',
reactive: false, reactive: false,
x: rect.x + 2, // Adjust for border width x: rect.x - 2, // Adjust for border width
y: rect.y - 2, y: rect.y - 2,
width: rect.width + 2, width: rect.width + 4, // Increased to accommodate border
height: rect.height + 2, height: rect.height + 4,
// Initial style with default color.ts
// style: `border: 4px solid hsl(${this.hue}, 100%, 50%); border-radius: 5px;`,
style: `border: 2px solid rgba(0, 0, 0, 0.8); border-radius: 3px;`
}); });
// this.borderActor = new St.BorderImage({
//
// })
// Add the border actor to the UI group // Add the border actor to the UI group
Main.layoutManager.uiGroup.add_child(this.borderActor); global.window_group.add_child(this.borderActor);
// Main.layoutManager.uiGroup.add_child(this.borderActor);
// Listen to window's changes in position and size // Listen to window's changes in position and size
this.focusWindowSignals?.push(window.connect('position-changed', () => this._updateBorderPosition(window))); this.focusWindowSignals?.push(window.connect('position-changed', () => this._updateBorderPosition(window)));
@@ -76,8 +94,9 @@ export default class ActiveBorderExtension extends Extension {
this.focusWindowSignals?.push(window.connect('unmanaged', () => this._clearBorder())); this.focusWindowSignals?.push(window.connect('unmanaged', () => this._clearBorder()));
this._updateBorderPosition(window); this._updateBorderPosition(window);
// Add the effect to the window
// actor.add_effect_with_name('bor/der-effect', borderEffect); // Start the color.ts cycling
this._startColorCycle();
} }
_updateBorderPosition(window: Meta.Window) { _updateBorderPosition(window: Meta.Window) {
@@ -86,11 +105,14 @@ export default class ActiveBorderExtension extends Extension {
const rect = window.get_frame_rect(); const rect = window.get_frame_rect();
if (!rect) return; if (!rect) return;
this.borderActor.set_position(rect.x + 2, rect.y - 2); this.borderActor.set_position(rect.x - 2, rect.y - 2);
this.borderActor.set_size(rect.width - 2, rect.height + 2); this.borderActor.set_size(rect.width + 4, rect.height + 4);
} }
_clearBorder() { _clearBorder() {
// Stop the color.ts cycling
this._stopColorCycle();
if (this.borderActor) { if (this.borderActor) {
this.borderActor.destroy(); this.borderActor.destroy();
this.borderActor = null; this.borderActor = null;
@@ -107,7 +129,7 @@ export default class ActiveBorderExtension extends Extension {
disable() { disable() {
console.log("DISABLED PRETTY BORDERS!") console.log("DISABLED PRETTY BORDERS!")
// Disconnect the signal and remove any existing borders // Disconnect the focus signal and remove any existing borders
if (this._focusSignal) { if (this._focusSignal) {
global.display.disconnect(this._focusSignal); global.display.disconnect(this._focusSignal);
this._focusSignal = null; this._focusSignal = null;
@@ -118,4 +140,44 @@ export default class ActiveBorderExtension extends Extension {
this.lastFocusedWindow = null; this.lastFocusedWindow = null;
} }
// Start the color.ts cycling using GLib.timeout_add
_startColorCycle() {
if (this.colorTimeoutId === null) {
// Update every 100 milliseconds
this.colorTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 33, () => {
this._updateColor();
// Continue the timeout
return GLib.SOURCE_CONTINUE;
});
}
}
_getStyleRGBA() {
let rgb = RGBColor.fromHSL(this.currentColor)
return `border: 3px solid rgba(${rgb.r}, ${rgb.b}, ${rgb.g}, ${rgb.a}); border-radius: 10px;`
}
// Stop the color.ts cycling
_stopColorCycle() {
if (this.colorTimeoutId !== null) {
GLib.source_remove(this.colorTimeoutId);
this.colorTimeoutId = null;
}
}
// Update the border color.ts based on the current hue
_updateColor() {
if (!this.borderActor) return;
// console.log("updating color.ts")
// console.log(this.borderActor.get_style());
// Increment hue and wrap around at 360
this.currentColor.h = (this.currentColor.h + 1) % 360;
// Update the border color.ts
this.borderActor.set_style(this._getStyleRGBA());
return true; // Continue the timeout
}
} }
+15 -15
View File
@@ -1,14 +1,14 @@
/* Add your custom extension styling here */ /* Add your custom extension styling here */
.active-window-border { .active-window-border {
border: 2px solid rgba(191, 0, 255, 0.8); /*border: 2px solid rgba(191, 0, 255, 0.8);*/
border-radius: 3px; /*border-radius: 3px;*/
border-image-source: linear-gradient(to left, #743ad5, #d53a9d); /* border-image-source: linear-gradient(to left, #743ad5, #d53a9d);*/
/*border: 4px solid transparent;*/ /* !*border: 4px solid transparent;*!*/
/*border-radius: 5px;*/ /* !*border-radius: 5px;*!*/
/*/* Gradient border using border-image */ /* !*!* Gradient border using border-image *!*/
border-image: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1; /* border-image: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1;*/
} }
@@ -16,14 +16,14 @@
/* border-image-source: linear-gradient(to left, #743ad5, #d53a9d);*/ /* border-image-source: linear-gradient(to left, #743ad5, #d53a9d);*/
/*}*/ /*}*/
@keyframes rainbow-border { /*@keyframes rainbow-border {*/
0% { /* 0% {*/
border-image: linear-gradient(0deg, red, orange, yellow, green, blue, indigo, violet, red) 1; /* border-image: linear-gradient(0deg, red, orange, yellow, green, blue, indigo, violet, red) 1;*/
} /* }*/
100% { /* 100% {*/
border-image: linear-gradient(360deg, red, orange, yellow, green, blue, indigo, violet, red) 1; /* border-image: linear-gradient(360deg, red, orange, yellow, green, blue, indigo, violet, red) 1;*/
} /* }*/
} /*}*/
/*.active-window-border {*/ /*.active-window-border {*/
/* border: 4px solid transparent;*/ /* border: 4px solid transparent;*/
+1
View File
@@ -15,6 +15,7 @@
], ],
"files": [ "files": [
"extension.ts", "extension.ts",
"color.ts"
// "prefs.ts" // "prefs.ts"
], ],
} }