From 5a6c3ccd7261b2aed1bb4042c324802ce6e67354 Mon Sep 17 00:00:00 2001 From: Lucas Oskorep Date: Fri, 17 Oct 2025 01:25:47 -0400 Subject: [PATCH] Finish adding debugging command and ability to swap the orientation of a container --- extension.ts | 14 +++ ...ome.shell.extensions.aerospike.gschema.xml | 6 + src/prefs/prefs.ts | 9 ++ src/wm/container.ts | 8 ++ src/wm/window.ts | 5 - src/wm/windowManager.ts | 108 +++++++++++++++++- 6 files changed, 141 insertions(+), 9 deletions(-) diff --git a/extension.ts b/extension.ts index 98e45f5..afd68eb 100644 --- a/extension.ts +++ b/extension.ts @@ -58,6 +58,11 @@ export default class aerospike extends Extension { this.refreshKeybinding('print-tree'); }); + this.settings.connect('changed::toggle-orientation', () => { + log(`Toggle orientation keybinding changed to: ${this.settings.get_strv('toggle-orientation')}`); + this.refreshKeybinding('toggle-orientation'); + }); + this.settings.connect('changed::dropdown-option', () => { log(`Dropdown option changed to: ${this.settings.get_string('dropdown-option')}`); }); @@ -98,6 +103,11 @@ export default class aerospike extends Extension { this.windowManager.printTreeStructure(); }); break; + case 'toggle-orientation': + this.bindKeybinding('toggle-orientation', () => { + this.windowManager.toggleActiveContainerOrientation(); + }); + break; } } @@ -128,6 +138,10 @@ export default class aerospike extends Extension { this.bindKeybinding('print-tree', () => { this.windowManager.printTreeStructure(); }); + + this.bindKeybinding('toggle-orientation', () => { + this.windowManager.toggleActiveContainerOrientation(); + }); } private bindKeybinding(settingName: string, callback: () => void) { diff --git a/schemas/org.gnome.shell.extensions.aerospike.gschema.xml b/schemas/org.gnome.shell.extensions.aerospike.gschema.xml index 6fbc805..2c31914 100644 --- a/schemas/org.gnome.shell.extensions.aerospike.gschema.xml +++ b/schemas/org.gnome.shell.extensions.aerospike.gschema.xml @@ -43,5 +43,11 @@ Prints the current tree of containers and windows per monitor to logs + + comma']]]> + Toggle active container orientation + Toggles the orientation of the container holding the active window between horizontal and vertical + + \ No newline at end of file diff --git a/src/prefs/prefs.ts b/src/prefs/prefs.ts index fad60c6..bfee9e5 100644 --- a/src/prefs/prefs.ts +++ b/src/prefs/prefs.ts @@ -164,6 +164,15 @@ export default class AerospikeExtensions extends ExtensionPreferences { }) ); + keybindingsGroup.add( + new EntryRow({ + title: _('Toggle Orientation'), + settings: settings, + bind: 'toggle-orientation', + map: keybindingMap + }) + ); + } diff --git a/src/wm/container.ts b/src/wm/container.ts index 159d477..4098cb3 100644 --- a/src/wm/container.ts +++ b/src/wm/container.ts @@ -30,6 +30,14 @@ export default class WindowContainer { this.tileWindows(); } + toggleOrientation(): void { + this._orientation = this._orientation === Orientation.HORIZONTAL + ? Orientation.VERTICAL + : Orientation.HORIZONTAL; + Logger.info(`Container orientation toggled to ${this._orientation === Orientation.HORIZONTAL ? 'HORIZONTAL' : 'VERTICAL'}`); + this.tileWindows(); + } + addWindow(winWrap: WindowWrapper): void { // Add window to managed windows this._tiledItems.push(winWrap); diff --git a/src/wm/window.ts b/src/wm/window.ts index 5fab360..70bb350 100644 --- a/src/wm/window.ts +++ b/src/wm/window.ts @@ -85,11 +85,6 @@ export class WindowWrapper { } }), - this._window.connect('notify::has-focus', () => { - if (this._window.has_focus()) { - windowManager._activeWindowId = windowId; - } - }), this._window.connect('notify::maximized-horizontally', () => { if (this._window.is_maximized()) { Logger.log(`Window maximized: ${windowId}`); diff --git a/src/wm/windowManager.ts b/src/wm/windowManager.ts index 97ec27f..7eec9a9 100644 --- a/src/wm/windowManager.ts +++ b/src/wm/windowManager.ts @@ -65,6 +65,9 @@ export default class WindowManager implements IWindowManager { } this.captureExistingWindows(); + + // Sync the initially focused window + this.syncActiveWindow(); } instantiateDisplaySignals(): void { @@ -87,6 +90,9 @@ export default class WindowManager implements IWindowManager { global.display.connect('window-created', (display, window) => { this.handleWindowCreated(display, window); }), + global.display.connect('notify::focus-window', () => { + this.syncActiveWindow(); + }), global.display.connect("showing-desktop-changed", () => { Logger.log("SHOWING DESKTOP CHANGED"); @@ -417,6 +423,81 @@ export default class WindowManager implements IWindowManager { * @returns The window ID of the active window, or null if no window is active */ public syncActiveWindow(): number | null { + const focusWindow = global.display.focus_window; + if (focusWindow) { + this._activeWindowId = focusWindow.get_id(); + Logger.debug(`Active window changed to: ${this._activeWindowId} (${focusWindow.get_title()})`); + } else { + this._activeWindowId = null; + Logger.debug('No active window'); + } + return this._activeWindowId; + } + + /** + * Toggles the orientation of the active container (the container holding the active window) + */ + public toggleActiveContainerOrientation(): void { + if (this._activeWindowId === null) { + Logger.warn("No active window, cannot toggle container orientation"); + return; + } + + // Find the active window's container + const activeContainer = this._findActiveContainer(); + if (activeContainer) { + activeContainer.toggleOrientation(); + } else { + Logger.warn("Could not find container for active window"); + } + } + + /** + * Finds the container that directly contains the active window + * @returns The container holding the active window, or null if not found + */ + private _findActiveContainer(): WindowContainer | null { + if (this._activeWindowId === null) { + return null; + } + + for (const monitor of this._monitors.values()) { + const activeWorkspaceIndex = global.workspace_manager.get_active_workspace().index(); + const workspace = monitor._workspaces[activeWorkspaceIndex]; + + // Check if the window is directly in the workspace container + const windowWrapper = workspace.getWindow(this._activeWindowId); + if (windowWrapper) { + // Try to find the parent container + const container = this._findContainerHoldingWindow(workspace, this._activeWindowId); + return container; + } + } + + return null; + } + + /** + * Recursively finds the container that directly contains a specific window + * @param container The container to search + * @param windowId The window ID to find + * @returns The container that directly contains the window, or null if not found + */ + private _findContainerHoldingWindow(container: WindowContainer, windowId: number): WindowContainer | null { + // Check if this container directly contains the window + for (const item of container._tiledItems) { + if (item instanceof WindowContainer) { + // Recursively search nested containers + const result = this._findContainerHoldingWindow(item, windowId); + if (result) { + return result; + } + } else if (item.getWindowId() === windowId) { + // Found it! Return this container as it directly holds the window + return container; + } + } + return null; } @@ -427,13 +508,24 @@ export default class WindowManager implements IWindowManager { Logger.info("=".repeat(80)); Logger.info("WINDOW TREE STRUCTURE"); Logger.info("=".repeat(80)); + Logger.info(`Active Window ID: ${this._activeWindowId ?? 'none'}`); + Logger.info("=".repeat(80)); + + const activeWorkspaceIndex = global.workspace_manager.get_active_workspace().index(); this._monitors.forEach((monitor: Monitor, monitorId: number) => { - Logger.info(`Monitor ${monitorId}:`); + const isActiveMonitor = this._activeWindowId !== null && + monitor.getWindow(this._activeWindowId) !== undefined; + const monitorMarker = isActiveMonitor ? ' *' : ''; + + Logger.info(`Monitor ${monitorId}${monitorMarker}:`); Logger.info(` Work Area: x=${monitor._workArea.x}, y=${monitor._workArea.y}, w=${monitor._workArea.width}, h=${monitor._workArea.height}`); monitor._workspaces.forEach((workspace, workspaceIndex) => { - Logger.info(` Workspace ${workspaceIndex}:`); + const isActiveWorkspace = workspaceIndex === activeWorkspaceIndex; + const workspaceMarker = isActiveWorkspace && isActiveMonitor ? ' *' : ''; + + Logger.info(` Workspace ${workspaceIndex}${workspaceMarker}:`); Logger.info(` Orientation: ${workspace._orientation === 0 ? 'HORIZONTAL' : 'VERTICAL'}`); Logger.info(` Items: ${workspace._tiledItems.length}`); @@ -454,13 +546,21 @@ export default class WindowManager implements IWindowManager { container._tiledItems.forEach((item: any, index: number) => { if (item instanceof WindowContainer) { - Logger.info(`${indent}[${index}] Container (${item._orientation === 0 ? 'HORIZONTAL' : 'VERTICAL'}):`); + // Check if this container contains the active window + const containsActiveWindow = this._activeWindowId !== null && + item.getWindow(this._activeWindowId) !== undefined; + const containerMarker = containsActiveWindow ? ' *' : ''; + + Logger.info(`${indent}[${index}] Container (${item._orientation === 0 ? 'HORIZONTAL' : 'VERTICAL'})${containerMarker}:`); Logger.info(`${indent} Items: ${item._tiledItems.length}`); Logger.info(`${indent} Work Area: x=${item._workArea.x}, y=${item._workArea.y}, w=${item._workArea.width}, h=${item._workArea.height}`); this._printContainerTree(item, indentLevel + 4); } else { const window = item.getWindow(); - Logger.info(`${indent}[${index}] Window ID: ${item.getWindowId()}`); + const isActiveWindow = this._activeWindowId === item.getWindowId(); + const windowMarker = isActiveWindow ? ' *' : ''; + + Logger.info(`${indent}[${index}] Window ID: ${item.getWindowId()}${windowMarker}`); Logger.info(`${indent} Title: "${window.get_title()}"`); Logger.info(`${indent} Class: ${window.get_wm_class()}`); const rect = item.getRect();