From 0bdb4af0e63675083a6862194ca090c0aa877346 Mon Sep 17 00:00:00 2001 From: Peter Fajdiga Date: Fri, 25 Aug 2023 15:27:16 +0200 Subject: [PATCH] create `ClientState` namespace --- src/world/ClientManager.ts | 32 ++++----- src/world/ClientStateDocked.ts | 23 ------- src/world/ClientStateManager.ts | 30 -------- src/world/ClientStateTiled.ts | 111 ------------------------------ src/world/ClientWrapper.ts | 12 ++-- src/world/clientstate/Docked.ts | 25 +++++++ src/world/clientstate/Manager.ts | 32 +++++++++ src/world/clientstate/Tiled.ts | 113 +++++++++++++++++++++++++++++++ 8 files changed, 192 insertions(+), 186 deletions(-) delete mode 100644 src/world/ClientStateDocked.ts delete mode 100644 src/world/ClientStateManager.ts delete mode 100644 src/world/ClientStateTiled.ts create mode 100644 src/world/clientstate/Docked.ts create mode 100644 src/world/clientstate/Manager.ts create mode 100644 src/world/clientstate/Tiled.ts diff --git a/src/world/ClientManager.ts b/src/world/ClientManager.ts index 408059a..4ab7d3b 100644 --- a/src/world/ClientManager.ts +++ b/src/world/ClientManager.ts @@ -24,17 +24,17 @@ class ClientManager { console.assert(!this.hasClient(kwinClient)); const client = new ClientWrapper( kwinClient, - new ClientStateFloating(), + new ClientState.Floating(), this.findTransientFor(kwinClient), this.windowRuleEnforcer.initClientSignalManager(this.world, kwinClient), ); this.clientMap.set(kwinClient, client); if (kwinClient.dock) { - client.stateManager.setState(new ClientStateDocked(this.world, kwinClient), false); + client.stateManager.setState(new ClientState.Docked(this.world, kwinClient), false); } else if (this.windowRuleEnforcer.shouldTile(kwinClient)) { const grid = this.desktopManager.getDesktopForClient(client.kwinClient).grid; - client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false); + client.stateManager.setState(new ClientState.Tiled(this.world, client, grid), false); } } @@ -66,8 +66,8 @@ class ClientManager { if (client === undefined) { return; } - if (client.stateManager.getState() instanceof ClientStateTiled) { - client.stateManager.setState(new ClientStateTiledMinimized(), kwinClient === this.lastFocusedClient); + if (client.stateManager.getState() instanceof ClientState.Tiled) { + client.stateManager.setState(new ClientState.TiledMinimized(), kwinClient === this.lastFocusedClient); } } @@ -76,9 +76,9 @@ class ClientManager { if (client === undefined) { return; } - if (client.stateManager.getState() instanceof ClientStateTiledMinimized) { + if (client.stateManager.getState() instanceof ClientState.TiledMinimized) { const grid = this.desktopManager.getDesktopForClient(client.kwinClient).grid; - client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false); + client.stateManager.setState(new ClientState.Tiled(this.world, client, grid), false); } } @@ -87,11 +87,11 @@ class ClientManager { if (client === undefined) { return; } - if (client.stateManager.getState() instanceof ClientStateTiled) { + if (client.stateManager.getState() instanceof ClientState.Tiled) { return; } const grid = this.desktopManager.getDesktopForClient(client.kwinClient).grid; - client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false); + client.stateManager.setState(new ClientState.Tiled(this.world, client, grid), false); } public untileClient(kwinClient: AbstractClient) { @@ -99,8 +99,8 @@ class ClientManager { if (client === undefined) { return; } - if (client.stateManager.getState() instanceof ClientStateTiled) { - client.stateManager.setState(new ClientStateFloating(), false); + if (client.stateManager.getState() instanceof ClientState.Tiled) { + client.stateManager.setState(new ClientState.Floating(), false); } } @@ -111,12 +111,12 @@ class ClientManager { } const clientState = client.stateManager.getState(); - if (clientState instanceof ClientStateFloating && Clients.canTileEver(kwinClient)) { + if (clientState instanceof ClientState.Floating && Clients.canTileEver(kwinClient)) { Clients.makeTileable(kwinClient); const grid = this.desktopManager.getDesktopForClient(client.kwinClient).grid; - client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false); - } else if (clientState instanceof ClientStateTiled) { - client.stateManager.setState(new ClientStateFloating(), false); + client.stateManager.setState(new ClientState.Tiled(this.world, client, grid), false); + } else if (clientState instanceof ClientState.Tiled) { + client.stateManager.setState(new ClientState.Floating(), false); } } @@ -143,7 +143,7 @@ class ClientManager { private findTiledWindowOfClient(client: ClientWrapper, followTransient: boolean): Window|null { const clientState = client.stateManager.getState(); - if (clientState instanceof ClientStateTiled) { + if (clientState instanceof ClientState.Tiled) { return clientState.window; } else if (followTransient && client.transientFor !== null) { return this.findTiledWindowOfClient(client.transientFor, true); diff --git a/src/world/ClientStateDocked.ts b/src/world/ClientStateDocked.ts deleted file mode 100644 index b4c99c1..0000000 --- a/src/world/ClientStateDocked.ts +++ /dev/null @@ -1,23 +0,0 @@ -class ClientStateDocked { - private readonly world: World; - private readonly signalManager: SignalManager; - - constructor(world: World, kwinClient: AbstractClient) { - this.world = world; - this.signalManager = ClientStateDocked.initSignalManager(world, kwinClient); - world.onScreenResized(); - } - - public destroy(passFocus: boolean) { - this.signalManager.destroy(); - this.world.onScreenResized(); - } - - private static initSignalManager(world: World, kwinClient: AbstractClient) { - const manager = new SignalManager(); - manager.connect(kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => { - world.onScreenResized(); - }); - return manager; - } -} diff --git a/src/world/ClientStateManager.ts b/src/world/ClientStateManager.ts deleted file mode 100644 index 8269f7c..0000000 --- a/src/world/ClientStateManager.ts +++ /dev/null @@ -1,30 +0,0 @@ -class ClientStateManager { - private state: ClientState; - - constructor(initialState: ClientState) { - this.state = initialState; - } - - public setState(newState: ClientState, passFocus: boolean) { - this.state.destroy(passFocus); - this.state = newState; - } - - public getState() { - return this.state; - } - - public destroy(passFocus: boolean) { - this.state.destroy(passFocus); - } -} - -type ClientState = ClientStateTiled | ClientStateTiledMinimized | ClientStateFloating | ClientStateDocked; - -class ClientStateTiledMinimized { - public destroy(passFocus: boolean) {} -} - -class ClientStateFloating { - public destroy(passFocus: boolean) {} -} diff --git a/src/world/ClientStateTiled.ts b/src/world/ClientStateTiled.ts deleted file mode 100644 index c462f8d..0000000 --- a/src/world/ClientStateTiled.ts +++ /dev/null @@ -1,111 +0,0 @@ -class ClientStateTiled { - public readonly window: Window; - private readonly signalManager: SignalManager; - - constructor(world: World, client: ClientWrapper, grid: Grid) { - client.prepareForTiling(); - - const column = new Column(grid, grid.getLastFocusedColumn() ?? grid.getLastColumn()); - const window = new Window(client, column); - - this.window = window; - this.signalManager = ClientStateTiled.initSignalManager(world, window); - } - - public destroy(passFocus: boolean) { - this.signalManager.destroy(); - - const window = this.window; - const grid = window.column.grid; - const clientWrapper = window.client; - window.destroy(passFocus); - - clientWrapper.prepareForFloating(grid.desktop.clientArea); - } - - private static initSignalManager(world: World, window: Window) { - const client = window.client; - const kwinClient = client.kwinClient; - const manager = new SignalManager(); - - manager.connect(kwinClient.desktopChanged, () => { - world.do((clientManager, desktopManager) => { - if (kwinClient.desktop === -1) { - // windows on all desktops are not supported - clientManager.untileClient(kwinClient); - return; - } - ClientStateTiled.moveWindowToCorrectGrid(desktopManager, window); - }); - }); - - manager.connect(kwinClient.activitiesChanged, (kwinClient: AbstractClient) => { - world.do((clientManager, desktopManager) => { - if (kwinClient.activities.length !== 1) { - // windows on multiple activities are not supported - clientManager.untileClient(kwinClient); - return; - } - ClientStateTiled.moveWindowToCorrectGrid(desktopManager, window); - }); - }) - - let lastResize = false; - manager.connect(kwinClient.moveResizedChanged, () => { - world.do((clientManager, desktopManager) => { - if (world.untileOnDrag && kwinClient.move) { - clientManager.untileClient(kwinClient); - return; - } - - const grid = window.column.grid; - const resize = kwinClient.resize; - if (!lastResize && resize) { - grid.onUserResizeStarted(); - } - if (lastResize && !resize) { - grid.onUserResizeFinished(); - } - lastResize = resize; - }); - }); - - let cursorChangedAfterResizeStart = false; - manager.connect(kwinClient.moveResizeCursorChanged, () => { - cursorChangedAfterResizeStart = true; - }); - manager.connect(kwinClient.clientStartUserMovedResized, () => { - cursorChangedAfterResizeStart = false; - }); - - manager.connect(kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => { - world.do((clientManager, desktopManager) => { - const desktop = window.column.grid.desktop; - if (kwinClient.resize) { - window.onUserResize(oldGeometry, !cursorChangedAfterResizeStart); - } else { - const maximized = rectEqual(kwinClient.frameGeometry, desktop.clientArea); - if (!client.isManipulatingGeometry() && !kwinClient.fullScreen && !maximized) { - window.onFrameGeometryChanged(oldGeometry); - } - } - }); - }); - - return manager; - } - - private static moveWindowToCorrectGrid(desktopManager: DesktopManager, window: Window) { - const kwinClient = window.client.kwinClient; - - const oldGrid = window.column.grid; - const newGrid = desktopManager.getDesktopForClient(kwinClient).grid; - if (oldGrid === newGrid) { - // window already on the correct grid - return; - } - - const newColumn = new Column(newGrid, newGrid.getLastFocusedColumn() ?? newGrid.getLastColumn()); - window.moveToColumn(newColumn); - } -} diff --git a/src/world/ClientWrapper.ts b/src/world/ClientWrapper.ts index 6208b39..9682a14 100644 --- a/src/world/ClientWrapper.ts +++ b/src/world/ClientWrapper.ts @@ -1,6 +1,6 @@ class ClientWrapper { public readonly kwinClient: AbstractClient; - public readonly stateManager: ClientStateManager; + public readonly stateManager: ClientState.Manager; public transientFor: ClientWrapper | null; private readonly transients: ClientWrapper[]; private readonly signalManager: SignalManager; @@ -10,12 +10,12 @@ class ClientWrapper { constructor( kwinClient: AbstractClient, - initialState: ClientState, + initialState: ClientState.State, transientFor: ClientWrapper | null, rulesSignalManager: SignalManager | null, ) { this.kwinClient = kwinClient; - this.stateManager = new ClientStateManager(initialState); + this.stateManager = new ClientState.Manager(initialState); this.transientFor = transientFor; this.transients = []; if (transientFor !== null) { @@ -39,7 +39,7 @@ class ClientWrapper { private moveTransient(dx: number, dy: number, desktopNumber: number) { // TODO: prevent moving off the grid - if (this.stateManager.getState() instanceof ClientStateFloating) { + if (this.stateManager.getState() instanceof ClientState.Floating) { if (this.kwinClient.desktop === desktopNumber) { const frame = this.kwinClient.frameGeometry; this.kwinClient.frameGeometry = Qt.rect( @@ -123,7 +123,7 @@ class ClientWrapper { public ensureTransientsVisible(screenSize: QRect) { for (const transient of this.transients) { - if (transient.stateManager.getState() instanceof ClientStateFloating) { + if (transient.stateManager.getState() instanceof ClientState.Floating) { transient.ensureVisible(screenSize); transient.ensureTransientsVisible(screenSize); } @@ -159,7 +159,7 @@ class ClientWrapper { private static initSignalManager(client: ClientWrapper) { const manager = new SignalManager(); manager.connect(client.kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => { - if (client.stateManager.getState() instanceof ClientStateTiled) { + if (client.stateManager.getState() instanceof ClientState.Tiled) { const newGeometry = client.kwinClient.frameGeometry; const oldCenterX = oldGeometry.x + oldGeometry.width/2; const oldCenterY = oldGeometry.y + oldGeometry.height/2; diff --git a/src/world/clientstate/Docked.ts b/src/world/clientstate/Docked.ts new file mode 100644 index 0000000..86b51c5 --- /dev/null +++ b/src/world/clientstate/Docked.ts @@ -0,0 +1,25 @@ +namespace ClientState { + export class Docked { + private readonly world: World; + private readonly signalManager: SignalManager; + + constructor(world: World, kwinClient: AbstractClient) { + this.world = world; + this.signalManager = ClientState.Docked.initSignalManager(world, kwinClient); + world.onScreenResized(); + } + + public destroy(passFocus: boolean) { + this.signalManager.destroy(); + this.world.onScreenResized(); + } + + private static initSignalManager(world: World, kwinClient: AbstractClient) { + const manager = new SignalManager(); + manager.connect(kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => { + world.onScreenResized(); + }); + return manager; + } + } +} diff --git a/src/world/clientstate/Manager.ts b/src/world/clientstate/Manager.ts new file mode 100644 index 0000000..272cf64 --- /dev/null +++ b/src/world/clientstate/Manager.ts @@ -0,0 +1,32 @@ +namespace ClientState { + export class Manager { + private state: ClientState.State; + + constructor(initialState: ClientState.State) { + this.state = initialState; + } + + public setState(newState: ClientState.State, passFocus: boolean) { + this.state.destroy(passFocus); + this.state = newState; + } + + public getState() { + return this.state; + } + + public destroy(passFocus: boolean) { + this.state.destroy(passFocus); + } + } + + export type State = ClientState.Tiled | ClientState.TiledMinimized | ClientState.Floating | ClientState.Docked; + + export class TiledMinimized { + public destroy(passFocus: boolean) {} + } + + export class Floating { + public destroy(passFocus: boolean) {} + } +} diff --git a/src/world/clientstate/Tiled.ts b/src/world/clientstate/Tiled.ts new file mode 100644 index 0000000..c253ece --- /dev/null +++ b/src/world/clientstate/Tiled.ts @@ -0,0 +1,113 @@ +namespace ClientState { + export class Tiled { + public readonly window: Window; + private readonly signalManager: SignalManager; + + constructor(world: World, client: ClientWrapper, grid: Grid) { + client.prepareForTiling(); + + const column = new Column(grid, grid.getLastFocusedColumn() ?? grid.getLastColumn()); + const window = new Window(client, column); + + this.window = window; + this.signalManager = ClientState.Tiled.initSignalManager(world, window); + } + + public destroy(passFocus: boolean) { + this.signalManager.destroy(); + + const window = this.window; + const grid = window.column.grid; + const clientWrapper = window.client; + window.destroy(passFocus); + + clientWrapper.prepareForFloating(grid.desktop.clientArea); + } + + private static initSignalManager(world: World, window: Window) { + const client = window.client; + const kwinClient = client.kwinClient; + const manager = new SignalManager(); + + manager.connect(kwinClient.desktopChanged, () => { + world.do((clientManager, desktopManager) => { + if (kwinClient.desktop === -1) { + // windows on all desktops are not supported + clientManager.untileClient(kwinClient); + return; + } + ClientState.Tiled.moveWindowToCorrectGrid(desktopManager, window); + }); + }); + + manager.connect(kwinClient.activitiesChanged, (kwinClient: AbstractClient) => { + world.do((clientManager, desktopManager) => { + if (kwinClient.activities.length !== 1) { + // windows on multiple activities are not supported + clientManager.untileClient(kwinClient); + return; + } + ClientState.Tiled.moveWindowToCorrectGrid(desktopManager, window); + }); + }) + + let lastResize = false; + manager.connect(kwinClient.moveResizedChanged, () => { + world.do((clientManager, desktopManager) => { + if (world.untileOnDrag && kwinClient.move) { + clientManager.untileClient(kwinClient); + return; + } + + const grid = window.column.grid; + const resize = kwinClient.resize; + if (!lastResize && resize) { + grid.onUserResizeStarted(); + } + if (lastResize && !resize) { + grid.onUserResizeFinished(); + } + lastResize = resize; + }); + }); + + let cursorChangedAfterResizeStart = false; + manager.connect(kwinClient.moveResizeCursorChanged, () => { + cursorChangedAfterResizeStart = true; + }); + manager.connect(kwinClient.clientStartUserMovedResized, () => { + cursorChangedAfterResizeStart = false; + }); + + manager.connect(kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => { + world.do((clientManager, desktopManager) => { + const desktop = window.column.grid.desktop; + if (kwinClient.resize) { + window.onUserResize(oldGeometry, !cursorChangedAfterResizeStart); + } else { + const maximized = rectEqual(kwinClient.frameGeometry, desktop.clientArea); + if (!client.isManipulatingGeometry() && !kwinClient.fullScreen && !maximized) { + window.onFrameGeometryChanged(oldGeometry); + } + } + }); + }); + + return manager; + } + + private static moveWindowToCorrectGrid(desktopManager: DesktopManager, window: Window) { + const kwinClient = window.client.kwinClient; + + const oldGrid = window.column.grid; + const newGrid = desktopManager.getDesktopForClient(kwinClient).grid; + if (oldGrid === newGrid) { + // window already on the correct grid + return; + } + + const newColumn = new Column(newGrid, newGrid.getLastFocusedColumn() ?? newGrid.getLastColumn()); + window.moveToColumn(newColumn); + } + } +}