From 39ddbcd2bc3ae944df41043cb05cbf82b188c550 Mon Sep 17 00:00:00 2001 From: Lucas Oskorep Date: Fri, 8 Nov 2024 19:54:19 -0500 Subject: [PATCH] feat: adding animation for the window border --- Makefile | 5 ++- color.ts | 73 +++++++++++++++++++++++++++++++++++ extension.ts | 102 +++++++++++++++++++++++++++++++++++++++---------- stylesheet.css | 30 +++++++-------- tsconfig.json | 1 + 5 files changed, 175 insertions(+), 36 deletions(-) create mode 100644 color.ts diff --git a/Makefile b/Makefile index f4a655f..11c5e00 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ $(NAME).zip: dist/extension.js dist/prefs.js schemas/gschemas.compiled @cp stylesheet.css dist/ @(cd dist && zip ../$(NAME).zip -9r .) + pack: $(NAME).zip install: $(NAME).zip @@ -33,4 +34,6 @@ clean: test: - @dbus-run-session -- gnome-shell --nested --wayland \ No newline at end of file + @dbus-run-session -- gnome-shell --nested --wayland + +install-and-test: install test diff --git a/color.ts b/color.ts new file mode 100644 index 0000000..9876a4b --- /dev/null +++ b/color.ts @@ -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; + } +} \ No newline at end of file diff --git a/extension.ts b/extension.ts index 2a8f0f7..bcaab88 100644 --- a/extension.ts +++ b/extension.ts @@ -4,7 +4,9 @@ import St from 'gi://St'; import Meta from 'gi://Meta'; import Shell from 'gi://Shell'; 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 { @@ -13,6 +15,10 @@ export default class ActiveBorderExtension extends Extension { lastFocusedWindow: Meta.Window | null; _focusSignal: number | null; + // New variables for color.ts cycling + colorTimeoutId: number | null; + currentColor: HSLColor; + constructor(metadata: ExtensionMetadata) { super(metadata); // Initialize instance variables @@ -20,25 +26,35 @@ export default class ActiveBorderExtension extends Extension { this.focusWindowSignals = []; this.lastFocusedWindow = null; this._focusSignal = null; + + // Initialize color.ts cycling variables + this.colorTimeoutId = null; + this.currentColor = new HSLColor(0, 1, .5); // Starting hue value } enable() { console.log("STARTING PRETTY BORDERS!") // Connect to the focus window signal to track the active window this._focusSignal = global.display.connect('notify::focus-window', () => { + console.log("Focus Changed") 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 this._updateBorder(global.display.focus_window); - } _updateBorder(window: Meta.Window) { console.log("UPDATING THE BORDER") - // Clear the previous border if there's a last focused window - // if (this.lastFocusedWindow) { - // this._clearBorder(this.lastFocusedWindow); - // } + // Clear the previous border this._clearBorder(); // Set a new border for the currently focused window if (window) { @@ -57,18 +73,20 @@ export default class ActiveBorderExtension extends Extension { // Create a new actor for the border using St.Widget this.borderActor = new St.Widget({ name: 'active-window-border', - style_class: 'active-window-border', + // style_class: 'active-window-border', reactive: false, - x: rect.x + 2, // Adjust for border width + x: rect.x - 2, // Adjust for border width y: rect.y - 2, - width: rect.width + 2, - height: rect.height + 2, + width: rect.width + 4, // Increased to accommodate border + 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 - 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 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._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) { @@ -86,11 +105,14 @@ export default class ActiveBorderExtension extends Extension { const rect = window.get_frame_rect(); if (!rect) return; - this.borderActor.set_position(rect.x + 2, rect.y - 2); - this.borderActor.set_size(rect.width - 2, rect.height + 2); + this.borderActor.set_position(rect.x - 2, rect.y - 2); + this.borderActor.set_size(rect.width + 4, rect.height + 4); } _clearBorder() { + // Stop the color.ts cycling + this._stopColorCycle(); + if (this.borderActor) { this.borderActor.destroy(); this.borderActor = null; @@ -107,7 +129,7 @@ export default class ActiveBorderExtension extends Extension { disable() { 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) { global.display.disconnect(this._focusSignal); this._focusSignal = null; @@ -118,4 +140,44 @@ export default class ActiveBorderExtension extends Extension { 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 + } + +} \ No newline at end of file diff --git a/stylesheet.css b/stylesheet.css index f6aafb5..a69d151 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,14 +1,14 @@ /* Add your custom extension styling here */ .active-window-border { - border: 2px solid rgba(191, 0, 255, 0.8); - border-radius: 3px; + /*border: 2px solid rgba(191, 0, 255, 0.8);*/ + /*border-radius: 3px;*/ - border-image-source: linear-gradient(to left, #743ad5, #d53a9d); - /*border: 4px solid transparent;*/ - /*border-radius: 5px;*/ +/* border-image-source: linear-gradient(to left, #743ad5, #d53a9d);*/ +/* !*border: 4px solid transparent;*!*/ +/* !*border-radius: 5px;*!*/ - /*/* Gradient border using border-image */ - border-image: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1; +/* !*!* Gradient border using border-image *!*/ +/* 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);*/ /*}*/ -@keyframes rainbow-border { - 0% { - border-image: linear-gradient(0deg, red, orange, yellow, green, blue, indigo, violet, red) 1; - } - 100% { - border-image: linear-gradient(360deg, red, orange, yellow, green, blue, indigo, violet, red) 1; - } -} +/*@keyframes rainbow-border {*/ +/* 0% {*/ +/* border-image: linear-gradient(0deg, red, orange, yellow, green, blue, indigo, violet, red) 1;*/ +/* }*/ +/* 100% {*/ +/* border-image: linear-gradient(360deg, red, orange, yellow, green, blue, indigo, violet, red) 1;*/ +/* }*/ +/*}*/ /*.active-window-border {*/ /* border: 4px solid transparent;*/ diff --git a/tsconfig.json b/tsconfig.json index 3aa880c..05ba72f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,7 @@ ], "files": [ "extension.ts", + "color.ts" // "prefs.ts" ], }