diff --git a/src/container.ts b/src/container.ts index e25f5d5..8809878 100644 --- a/src/container.ts +++ b/src/container.ts @@ -13,8 +13,8 @@ enum Orientation { export default class WindowContainer { _id: number; - _items: Map; - _minimizedItems: Map; + _tiledItems: (WindowWrapper | WindowContainer)[]; + _tiledWindowLookup: Map; _workspace: number; _orientation: Orientation = Orientation.HORIZONTAL; _workArea: Rect; @@ -22,8 +22,8 @@ export default class WindowContainer { constructor(monitorId: number, workspaceArea: Rect, workspace: number) { this._id = monitorId; this._workspace = workspace; - this._items = new Map(); - this._minimizedItems = new Map(); + this._tiledItems = []; + this._tiledWindowLookup = new Map(); this._workArea = workspaceArea; } @@ -33,47 +33,66 @@ export default class WindowContainer { move(rect: Rect): void { this._workArea = rect; - this._tileWindows(); + this.tileWindows(); } addWindow(winWrap: WindowWrapper): void { // Add window to managed windows - if (!winWrap.getWindow().minimized) { - this._items.set(winWrap.getWindowId(), winWrap); - queueEvent({ - name: "tiling-windows", - callback: () => { - this._tileWindows(); - } - }, 100) - } else { - this._minimizedItems.set(winWrap.getWindowId(), winWrap); - } + this._tiledItems.push(winWrap); + this._tiledWindowLookup.set(winWrap.getWindowId(), winWrap); + queueEvent({ + name: "tiling-windows", + callback: () => { + this.tileWindows(); + } + }, 100) + } - getWindow(win_id: number): WindowWrapper | WindowContainer | undefined { - return this._items.get(win_id) + getWindow(win_id: number): WindowWrapper | undefined { + if (this._tiledWindowLookup.has(win_id)) { + return this._tiledWindowLookup.get(win_id); + } + for (const item of this._tiledItems) { + if (item instanceof WindowContainer) { + const win = item.getWindow(win_id); + if (win) { + return win; + } + } else if (item.getWindowId() === win_id) { + return item; + } + } + return undefined + } + + _getIndexOfWindow(win_id: number) { + for (let i = 0; i < this._tiledItems.length; i++) { + const item = this._tiledItems[i]; + if (item instanceof WindowWrapper && item.getWindowId() === win_id) { + return i; + } + } + return -1 } removeWindow(win_id: number): void { - this._items.delete(win_id) - this._tileWindows() - } - - minimizeWindow(winWrap: WindowWrapper): void { - this._items.delete(winWrap.getWindowId()) - this._minimizedItems.set(winWrap.getWindowId(), winWrap) - } - - unminimizeWindow(winWrap: WindowWrapper): void { - if (this._minimizedItems.has(winWrap.getWindowId())) { - this._items.set(winWrap.getWindowId(), winWrap); - this._minimizedItems.delete(winWrap.getWindowId()); + if (this._tiledWindowLookup.has(win_id)) { + this._tiledWindowLookup.delete(win_id); + const index = this._getIndexOfWindow(win_id) + this._tiledItems.splice(index, 1); + } else { + for (const item of this._tiledItems) { + if (item instanceof WindowContainer) { + item.removeWindow(win_id); + } + } } + this.tileWindows() } disconnectSignals(): void { - this._items.forEach((item) => { + this._tiledItems.forEach((item) => { if (item instanceof WindowContainer) { item.disconnectSignals() } else { @@ -84,10 +103,11 @@ export default class WindowContainer { } removeAllWindows(): void { - this._items.clear() + this._tiledItems = [] + this._tiledWindowLookup.clear() } - _tileWindows() { + tileWindows() { Logger.log("TILING WINDOWS ON MONITOR", this._id) Logger.log("Workspace", this._workspace); @@ -97,18 +117,17 @@ export default class WindowContainer { let tilable = this._getTilableItems(); if (tilable.length !== 0) { - this._tileHorizontally(tilable, ) + this._tileItems(tilable) } return true } - _getTilableItems(): (WindowWrapper|WindowContainer)[] { - return Array.from(this._items.values()) + _getTilableItems(): (WindowWrapper | WindowContainer)[] { + return Array.from(this._tiledItems.values()) } - - _tileItems(windows: (WindowWrapper|WindowContainer)[]) { - if (windows.length === 0){ + _tileItems(windows: (WindowWrapper | WindowContainer)[]) { + if (windows.length === 0) { return; } if (this._orientation === Orientation.HORIZONTAL) { @@ -118,7 +137,7 @@ export default class WindowContainer { } } - _tileVertically(items: (WindowWrapper|WindowContainer)[]) { + _tileVertically(items: (WindowWrapper | WindowContainer)[]) { const containerHeight = Math.floor(this._workArea.height / items.length); items.forEach((item, index) => { @@ -139,7 +158,7 @@ export default class WindowContainer { }); } - _tileHorizontally(windows: (WindowWrapper|WindowContainer)[]) { + _tileHorizontally(windows: (WindowWrapper | WindowContainer)[]) { const windowWidth = Math.floor(this._workArea.width / windows.length); windows.forEach((item, index) => { diff --git a/src/monitor.ts b/src/monitor.ts index f46d7bf..4f8c6dd 100644 --- a/src/monitor.ts +++ b/src/monitor.ts @@ -12,21 +12,64 @@ export default class Monitor { _id: number; _workArea: Rect; - // _activeWorkspace: number; - // _workspaces: Map; + _workspaces: WindowContainer[] = []; constructor(monitorId: number) { this._id = monitorId; const workspace = global.workspace_manager.get_active_workspace(); this._workArea = workspace.get_work_area_for_monitor(this._id); - // this._activeWorkspace = workspace Logger.log("CREATING MONITOR", monitorId); - const workspaces = global.workspace_manager.get_n_workspaces(); - Logger.log("WORKSPACE COUNT", workspaces); - // this._rootContainer = new WindowContainer(monitorId, this._workArea, ); + Logger.log("WorkArea", this._workArea.x, this._workArea.y, this._workArea.width, this._workArea.height); + const workspaceCount = global.workspace_manager.get_n_workspaces() + Logger.log("Workspace Count", workspaceCount); + for (let i = 0; i < workspaceCount; i++) { + this._workspaces.push(new WindowContainer(monitorId, this._workArea, i)); + } + } + + disconnectSignals() { + for (const container of this._workspaces) { + container.disconnectSignals(); + } + } + + removeAllWindows(): void { + for (const container of this._workspaces) { + container.removeAllWindows(); + } + } + + getWindow(windowId: number): WindowWrapper | undefined { + for (const container of this._workspaces) { + const win = container.getWindow(windowId); + if (win) { + return win; + } + } + return undefined; + } + + removeWindow(winWrap: WindowWrapper) { + const windowId = winWrap.getWindowId(); + for (const container of this._workspaces) { + const win = container.getWindow(windowId); + if (win) { + container.removeWindow(windowId); + } + } + } + + addWindow(winWrap: WindowWrapper) { + const window_workspace = winWrap.getWindow().get_workspace().index(); + Logger.log("Adding window to workspace", window_workspace); + this._workspaces[window_workspace].addWindow(winWrap); + } + + tileWindows(): void { + this._workArea = global.workspace_manager.get_active_workspace().get_work_area_for_monitor(this._id); + const activeWorkspace = global.workspace_manager.get_active_workspace(); + this._workspaces[activeWorkspace.index()].move(this._workArea); + this._workspaces[activeWorkspace.index()].tileWindows() } - // removeAllWindows(): void { - // for (WindowContainer container of this._workspaces.values()) {} - // } } \ No newline at end of file diff --git a/src/window.ts b/src/window.ts index c24af9e..75e75a8 100644 --- a/src/window.ts +++ b/src/window.ts @@ -3,16 +3,22 @@ import Clutter from "gi://Clutter"; import {IWindowManager} from "./windowManager.js"; import {Logger} from "./utils/logger.js"; import {Rect} from "./utils/rect.js"; +import WindowContainer from "./container.js"; type WindowMinimizedHandler = (window: WindowWrapper) => void; +type WindowWorkspaceChangedHandler = (window: WindowWrapper) => void; export class WindowWrapper { readonly _window: Meta.Window; readonly _windowMinimizedHandler: WindowMinimizedHandler; + // readonly _windowWorkspaceChangedHandler: WindowWorkspaceChangedHandler; readonly _signals: number[]; - constructor(window: Meta.Window, winMinimized: WindowMinimizedHandler) { + constructor( + window: Meta.Window, + winMinimized: WindowMinimizedHandler + ) { this._window = window; this._signals = []; this._windowMinimizedHandler = winMinimized; @@ -47,16 +53,6 @@ export class WindowWrapper { } }), - this._window.connect( - 'workspace-changed', - (window) => { - const workspace = window.get_workspace(); - const workspaceIndex = workspace ? workspace.index() : -1; - console.log(`Window moved to workspace ${workspaceIndex}`); - }, - this - ); - , this._window.connect('notify::has-focus', () => { if (this._window.has_focus()) { windowManager._activeWindowId = windowId; @@ -69,6 +65,9 @@ export class WindowWrapper { Logger.log(`Window unmaximized: ${windowId}`); } }), + this._window.connect("workspace-changed", (_metaWindow) => { + Logger.log("WORKSPACE CHANGED FOR WINDOW", this._window.get_id()); + }), ); } diff --git a/src/windowManager.ts b/src/windowManager.ts index 6b32708..f5c017d 100644 --- a/src/windowManager.ts +++ b/src/windowManager.ts @@ -43,6 +43,8 @@ export default class WindowManager implements IWindowManager { _lockedSignalId: number | null; _isScreenLocked: boolean; + _minimizedItems: Map; + constructor() { this._displaySignals = []; this._windowManagerSignals = []; @@ -50,11 +52,13 @@ export default class WindowManager implements IWindowManager { this._overviewSignals = []; this._activeWindowId = null; this._grabbedWindowMonitor = _UNUSED_MONITOR_ID; - this._monitors = new Map(); + this._monitors = new Map(); this._sessionProxy = null; this._lockedSignalId = null; this._isScreenLocked = false; // Initialize to unlocked state + this._minimizedItems = new Map(); + } public enable(): void { @@ -84,11 +88,13 @@ export default class WindowManager implements IWindowManager { global.display.connect('window-created', (display, window) => { this.handleWindowCreated(display, window); }), + global.display.connect("showing-desktop-changed", () => { Logger.log("SHOWING DESKTOP CHANGED"); }), global.display.connect("workareas-changed", (display) => { - Logger.log("WORK AREAS CHANGED", display.); + Logger.log("WORK AREAS CHANGED", ); + console.log(display.get_workspace_manager().get_active_workspace_index()) }), global.display.connect("in-fullscreen-changed", () => { Logger.log("IN FULL SCREEN CHANGED"); @@ -146,23 +152,23 @@ export default class WindowManager implements IWindowManager { } removeAllWindows(): void { - //TODO: RECONNECT - // this._monitors.forEach((monitor: Monitor) => { - // monitor.removeAllWindows(); - // }) + this._monitors.forEach((monitor: Monitor) => { + monitor.removeAllWindows(); + }) + this._minimizedItems.clear(); } disconnectSignals(): void { this.disconnectDisplaySignals(); this.disconnectMonitorSignals(); + this.disconnectMinimizedSignals(); } disconnectMonitorSignals(): void { - //TODO: RECONNECT - // this._monitors.forEach((monitor: Monitor) => { - // monitor.disconnectSignals(); - // }) + this._monitors.forEach((monitor: Monitor) => { + monitor.disconnectSignals(); + }) } disconnectDisplaySignals(): void { @@ -180,6 +186,12 @@ export default class WindowManager implements IWindowManager { }) } + disconnectMinimizedSignals(): void { + this._minimizedItems.forEach((item) => { + item.disconnectWindowSignals(); + }) + } + handleGrabOpBegin(display: Meta.Display, window: Meta.Window, op: Meta.GrabOp): void { Logger.log("Grab Op Start"); @@ -204,15 +216,14 @@ export default class WindowManager implements IWindowManager { if (old_mon === undefined || new_mon === undefined) { return; } - //TODO: RECONNECT - // let wrapped = old_mon.getWindow(window.get_id()) - // if (wrapped === undefined) { - // wrapped = new WindowWrapper(window, this.handleWindowMinimized); - // } else { - // old_mon.removeWindow(window.get_id()) - // } - // new_mon.addWindow(wrapped) + let wrapped = old_mon.getWindow(window.get_id()) + if (wrapped === undefined) { + wrapped = new WindowWrapper(window, this.handleWindowMinimized); + } else { + old_mon.removeWindow(wrapped) + } + new_mon.addWindow(wrapped) } this._tileMonitors(); Logger.info("monitor_start and monitor_end", this._grabbedWindowMonitor, window.get_monitor()); @@ -220,20 +231,25 @@ export default class WindowManager implements IWindowManager { public handleWindowMinimized(winWrap: WindowWrapper): void { Logger.warn("WARNING MINIMIZING WINDOW"); - Logger.log("WARNING MINIMIZED", winWrap); + Logger.log("WARNING MINIMIZED", JSON.stringify(winWrap)); const monitor_id = winWrap.getWindow().get_monitor() Logger.log("WARNING MINIMIZED", monitor_id); Logger.warn("WARNING MINIMIZED", this._monitors); - //TODO: RECONNECT - // this._monitors.get(monitor_id)?.minimizeWindow(winWrap); + + this._minimizedItems.set(winWrap.getWindowId(), winWrap); + this._monitors.get(monitor_id)?.removeWindow(winWrap); + + Logger.warn("WARNING MINIMIZED ITEMS", JSON.stringify(this._minimizedItems)); this._tileMonitors() } public handleWindowUnminimized(winWrap: WindowWrapper): void { Logger.log("WINDOW UNMINIMIZED"); - const monitor_id = winWrap.getWindow().get_monitor() - //TODO: RECONNECT - // this._monitors.get(monitor_id)?.unminimizeWindow(winWrap); + Logger.log("WINDOW UNMINIMIZED", winWrap == null); + // Logger.log("WINDOW UNMINIMIZED", winWrap); + // Logger.log("WINDOW UNMINIMIZED", winWrap.getWindowId()); + this._minimizedItems.delete(winWrap.getWindowId()); + this._addWindowWrapperToMonitor(winWrap); this._tileMonitors() } @@ -267,11 +283,11 @@ export default class WindowManager implements IWindowManager { */ handleWindowClosed(window: WindowWrapper): void { - // window.disconnectWindowSignals() const mon_id = window._window.get_monitor(); - //TODO: RECONNECT - // this._monitors.get(mon_id)?.removeWindow(window.getWindowId()); + this._monitors.get(mon_id)?.removeWindow(window); + + window.disconnectWindowSignals() // Remove from managed windows this.syncActiveWindow(); // Retile remaining windows @@ -284,17 +300,20 @@ export default class WindowManager implements IWindowManager { Logger.log("ADDING WINDOW TO MONITOR", window, window); var wrapper = new WindowWrapper(window, this.handleWindowMinimized) wrapper.connectWindowSignals(this); - //TODO: RECONNECT + this._addWindowWrapperToMonitor(wrapper); - // this._monitors.get(window.get_monitor())?.addWindow(wrapper) + } + _addWindowWrapperToMonitor(winWrap: WindowWrapper) { + if (winWrap.getWindow().minimized) { + this._minimizedItems.set(winWrap.getWindow().get_id(), winWrap); + } + this._monitors.get(winWrap.getWindow().get_monitor())?.addWindow(winWrap) } _tileMonitors(): void { for (const monitor of this._monitors.values()) { - //TODO: RECONNECT - - // monitor._tileWindows() + monitor.tileWindows() } }