diff --git a/src/controller/action.test.ts b/src/controller/action.test.ts index 3b1691b0..70b012d8 100644 --- a/src/controller/action.test.ts +++ b/src/controller/action.test.ts @@ -7,7 +7,7 @@ import { createMock } from "ts-auto-mock"; import { Engine } from "../engine"; import { WindowsLayout } from "../engine/layout"; -import Window from "../engine/window"; +import { EngineWindow } from "../engine/window"; import { NullLog } from "../util/log"; import * as Action from "./action"; @@ -89,9 +89,9 @@ describe("action", () => { describe("move window", () => { let fakeEngine: Engine; - let fakeCurrentWindow: Window; + let fakeCurrentWindow: EngineWindow; beforeEach(() => { - fakeCurrentWindow = createMock(); + fakeCurrentWindow = createMock(); fakeEngine = createMock({ swapOrder: jest.fn(), @@ -169,10 +169,10 @@ describe("action", () => { describe("window resize", () => { let fakeEngine: Engine; - let fakeCurrentWindow: Window; + let fakeCurrentWindow: EngineWindow; beforeEach(() => { - fakeCurrentWindow = createMock(); + fakeCurrentWindow = createMock(); fakeEngine = createMock({ resizeWindow: jest.fn(), @@ -313,7 +313,7 @@ describe("action", () => { describe("toggle floating", () => { it("executes correctly", () => { - const fakeCurrentWindow = createMock(); + const fakeCurrentWindow = createMock(); const fakeEngine = createMock({ toggleFloat: jest.fn(), currentWindow: jest.fn().mockReturnValue(fakeCurrentWindow), @@ -329,7 +329,7 @@ describe("action", () => { describe("push window into master area", () => { it("executes correctly", () => { - const fakeCurrentWindow = createMock(); + const fakeCurrentWindow = createMock(); const fakeEngine = createMock({ setMaster: jest.fn(), currentWindow: jest.fn().mockReturnValue(fakeCurrentWindow), @@ -348,10 +348,10 @@ describe("action", () => { describe("layout switching", () => { let fakeEngine: Engine; - let fakeCurrentWindow: Window; + let fakeCurrentWindow: EngineWindow; beforeEach(() => { - fakeCurrentWindow = createMock(); + fakeCurrentWindow = createMock(); fakeEngine = createMock({ cycleLayout: jest.fn(), diff --git a/src/controller/index.ts b/src/controller/index.ts index d2dd6d04..f8d24298 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT import { Engine, TilingEngine } from "../engine"; -import Window from "../engine/window"; +import { EngineWindow } from "../engine/window"; import { WindowState } from "../engine/window"; import { DriverContext, KWinDriver } from "../driver"; @@ -31,7 +31,7 @@ export interface Controller { /** * Current active window. In other words the window, that has focus. */ - currentWindow: Window | null; + currentWindow: EngineWindow | null; /** * Current screen. In other words the screen, that has focus. @@ -59,13 +59,13 @@ export interface Controller { * React to window geometry update * @param window the window whose geometry has changed */ - onWindowGeometryChanged(window: Window): void; + onWindowGeometryChanged(window: EngineWindow): void; /** * React to window resizing * @param window the window which is resized */ - onWindowResize(window: Window): void; + onWindowResize(window: EngineWindow): void; /** * React to window resize operation start. The window @@ -73,7 +73,7 @@ export interface Controller { * the window with the mouse by the window edges. * @param window the window which is being resized */ - onWindowResizeStart(window: Window): void; + onWindowResizeStart(window: EngineWindow): void; /** * React to window resize operation end. The window @@ -81,35 +81,35 @@ export interface Controller { * the window. * @param window the window which was dropped */ - onWindowResizeOver(window: Window): void; + onWindowResizeOver(window: EngineWindow): void; /** * React to window addition * @param window new added window */ - onWindowAdded(window: Window): void; + onWindowAdded(window: EngineWindow): void; /** * React to window removal * @param window the window which was removed */ - onWindowRemoved(window: Window): void; + onWindowRemoved(window: EngineWindow): void; /** * React to window maximization state change * @param window the window whose maximization state changed * @param maximized new maximization state */ - onWindowMaximizeChanged(window: Window, maximized: boolean): void; + onWindowMaximizeChanged(window: EngineWindow, maximized: boolean): void; // TODO: add docs - onWindowChanged(window: Window | null, comment?: string): void; + onWindowChanged(window: EngineWindow | null, comment?: string): void; /** * React to window being moved. * @param window the window, which it being moved. */ - onWindowMove(window: Window): void; + onWindowMove(window: EngineWindow): void; /** * React to window move operation start. The move operation starts @@ -117,7 +117,7 @@ export interface Controller { * the mouse's button being pressed * @param window the window which is being dragged */ - onWindowMoveStart(window: Window): void; + onWindowMoveStart(window: EngineWindow): void; /** * React to window move operation over. The move operation ends @@ -125,25 +125,25 @@ export interface Controller { * the mouse's button being released. * @param window the window which was being dragged */ - onWindowMoveOver(window: Window): void; + onWindowMoveOver(window: EngineWindow): void; /** * React to the window gaining focus, attention and love it deserves ❤️ * @param window the window which received the focus */ - onWindowFocused(window: Window): void; + onWindowFocused(window: EngineWindow): void; /** * React to the window shade state change * @param window the window whose state was changed */ - onWindowShadeChanged(window: Window): void; + onWindowShadeChanged(window: EngineWindow): void; /** * Ask engine to manage the window * @param win the window which needs to be managed. */ - manageWindow(win: Window): void; + manageWindow(win: EngineWindow): void; } export class TilingController implements Controller { @@ -178,11 +178,11 @@ export class TilingController implements Controller { return this.driver.screens; } - public get currentWindow(): Window | null { + public get currentWindow(): EngineWindow | null { return this.driver.currentWindow; } - public set currentWindow(value: Window | null) { + public set currentWindow(value: EngineWindow | null) { this.driver.currentWindow = value; } @@ -214,7 +214,7 @@ export class TilingController implements Controller { } } - public onWindowAdded(window: Window): void { + public onWindowAdded(window: EngineWindow): void { this.log.log(["onWindowAdded", { window }]); this.engine.manage(window); @@ -236,7 +236,7 @@ export class TilingController implements Controller { this.engine.arrange(); } - public onWindowRemoved(window: Window): void { + public onWindowRemoved(window: EngineWindow): void { this.log.log(["onWindowRemoved", { window }]); this.engine.unmanage(window); @@ -244,7 +244,7 @@ export class TilingController implements Controller { // Switch to next window if monocle with config.monocleMinimizeRest if ( - !window.window.isDialog && + !window.isDialog && !this.currentWindow && this.engine.isLayoutMonocleAndMinimizeRest() ) { @@ -257,15 +257,15 @@ export class TilingController implements Controller { } } - public onWindowMoveStart(_window: Window): void { + public onWindowMoveStart(_window: EngineWindow): void { /* do nothing */ } - public onWindowMove(_window: Window): void { + public onWindowMove(_window: EngineWindow): void { /* do nothing */ } - public onWindowMoveOver(window: Window): void { + public onWindowMoveOver(window: EngineWindow): void { this.log.log(["onWindowMoveOver", { window }]); /* swap window by dragging */ @@ -302,11 +302,11 @@ export class TilingController implements Controller { window.commit(); } - public onWindowResizeStart(_window: Window): void { + public onWindowResizeStart(_window: EngineWindow): void { /* do nothing */ } - public onWindowResize(window: Window): void { + public onWindowResize(window: EngineWindow): void { this.log.log(["onWindowResize", { window }]); if (this.config.adjustLayout && this.config.adjustLayoutLive) { if (window.state === WindowState.Tiled) { @@ -316,7 +316,7 @@ export class TilingController implements Controller { } } - public onWindowResizeOver(window: Window): void { + public onWindowResizeOver(window: EngineWindow): void { this.log.log(["onWindowResizeOver", { window }]); if (this.config.adjustLayout && window.tiled) { this.engine.adjustLayout(window); @@ -326,18 +326,21 @@ export class TilingController implements Controller { } } - public onWindowMaximizeChanged(_window: Window, _maximized: boolean): void { + public onWindowMaximizeChanged( + _window: EngineWindow, + _maximized: boolean + ): void { this.engine.arrange(); } - public onWindowGeometryChanged(window: Window): void { + public onWindowGeometryChanged(window: EngineWindow): void { this.log.log(["onWindowGeometryChanged", { window }]); this.engine.enforceSize(window); } // NOTE: accepts `null` to simplify caller. This event is a catch-all hack // by itself anyway. - public onWindowChanged(window: Window | null, comment?: string): void { + public onWindowChanged(window: EngineWindow | null, comment?: string): void { if (window) { this.log.log(["onWindowChanged", { window, comment }]); @@ -349,7 +352,7 @@ export class TilingController implements Controller { } } - public onWindowFocused(window: Window): void { + public onWindowFocused(window: EngineWindow): void { try { window.timestamp = new Date().getTime(); this.currentWindow = window; @@ -376,7 +379,7 @@ export class TilingController implements Controller { } } - public onWindowShadeChanged(win: Window): void { + public onWindowShadeChanged(win: EngineWindow): void { this.log.log(`onWindowShadeChanged, window: ${win}`); // NOTE: Float shaded windows and change their state back once unshaded @@ -391,7 +394,7 @@ export class TilingController implements Controller { this.engine.arrange(); } - public manageWindow(win: Window): void { + public manageWindow(win: EngineWindow): void { this.engine.manage(win); } diff --git a/src/driver/index.ts b/src/driver/index.ts index af482e30..54321294 100644 --- a/src/driver/index.ts +++ b/src/driver/index.ts @@ -10,7 +10,7 @@ import { KWinWindow } from "./window"; import { Controller } from "../controller"; import { Action } from "../controller/action"; -import Window from "../engine/window"; +import { EngineWindow, EngineWindowImpl } from "../engine/window"; import { WindowState } from "../engine/window"; @@ -21,7 +21,7 @@ export interface DriverContext { readonly screens: DriverSurface[]; currentSurface: DriverSurface; - currentWindow: Window | null; + currentWindow: EngineWindow | null; showNotification(text: string): void; @@ -63,12 +63,12 @@ export class KWinDriver implements DriverContext { } } - public get currentWindow(): Window | null { + public get currentWindow(): EngineWindow | null { const client = this.kwinApi.workspace.activeClient; return client ? this.windowMap.get(client) : null; } - public set currentWindow(window: Window | null) { + public set currentWindow(window: EngineWindow | null) { if (window !== null) { this.kwinApi.workspace.activeClient = ( window.window as KWinWindow @@ -94,7 +94,7 @@ export class KWinDriver implements DriverContext { } private controller: Controller; - private windowMap: WrapperMap; + private windowMap: WrapperMap; private entered: boolean; private qml: Bismuth.Qml.Main; @@ -126,7 +126,7 @@ export class KWinDriver implements DriverContext { this.windowMap = new WrapperMap( (client: KWin.Client) => KWinWindow.generateID(client), (client: KWin.Client) => - new Window( + new EngineWindowImpl( new KWinWindow(client, this.qml, this.kwinApi, this.config, this.log), this.config, this.log @@ -349,7 +349,7 @@ export class KWinDriver implements DriverContext { } } - private bindWindowEvents(window: Window, client: KWin.Client): void { + private bindWindowEvents(window: EngineWindow, client: KWin.Client): void { let moving = false; let resizing = false; diff --git a/src/engine/index.test.ts b/src/engine/index.test.ts index 7a74e638..faafe61b 100644 --- a/src/engine/index.test.ts +++ b/src/engine/index.test.ts @@ -15,7 +15,7 @@ import { Log } from "../util/log"; import Rect from "../util/rect"; import TileLayout from "./layout/tile_layout"; import LayoutStore from "./layout_store"; -import Window, { WindowState } from "./window"; +import { EngineWindow, WindowState } from "./window"; import WindowStore from "./window_store"; describe("arrange", () => { @@ -47,12 +47,12 @@ describe("arrangeScreen", () => { const configMock = createMock(); const engine = new TilingEngine(controllerMock, configMock, logMock); - const window1 = createMock({ + const window1 = createMock({ shouldFloat: false, state: WindowState.Undecided, }); - const window2 = createMock({ + const window2 = createMock({ shouldFloat: true, state: WindowState.Undecided, }); diff --git a/src/engine/index.ts b/src/engine/index.ts index c8becf73..1b4c9512 100644 --- a/src/engine/index.ts +++ b/src/engine/index.ts @@ -7,8 +7,7 @@ import MonocleLayout from "./layout/monocle_layout"; import LayoutStore from "./layout_store"; import WindowStore from "./window_store"; -import Window from "./window"; -import { WindowState } from "./window"; +import { EngineWindow, EngineWindowImpl, WindowState } from "./window"; import { Controller } from "../controller"; @@ -28,27 +27,27 @@ export interface Engine { windows: WindowStore; arrange(): void; - manage(window: Window): void; - unmanage(window: Window): void; - adjustLayout(basis: Window): void; + manage(window: EngineWindow): void; + unmanage(window: EngineWindow): void; + adjustLayout(basis: EngineWindow): void; resizeFloat( - window: Window, + window: EngineWindow, dir: "east" | "west" | "south" | "north", step: -1 | 1 ): void; resizeTile( - basis: Window, + basis: EngineWindow, dir: "east" | "west" | "south" | "north", step: -1 | 1 ): void; resizeWindow( - window: Window, + window: EngineWindow, dir: "east" | "west" | "south" | "north", step: -1 | 1 ): void; - enforceSize(window: Window): void; + enforceSize(window: EngineWindow): void; currentLayoutOnCurrentSurface(): WindowsLayout; - currentWindow(): Window | null; + currentWindow(): EngineWindow | null; /** * Focus next or previous window @@ -57,14 +56,14 @@ export interface Engine { */ focusOrder(step: -1 | 1, includeHidden: boolean): void; focusDir(dir: Direction): void; - swapOrder(window: Window, step: -1 | 1): void; + swapOrder(window: EngineWindow, step: -1 | 1): void; swapDirOrMoveFloat(dir: Direction): void; - setMaster(window: Window): void; - toggleFloat(window: Window): void; + setMaster(window: EngineWindow): void; + toggleFloat(window: EngineWindow): void; floatAll(srf: DriverSurface): void; cycleLayout(step: 1 | -1): void; setLayout(layoutClassID: string): void; - minimizeOthers(window: Window): void; + minimizeOthers(window: EngineWindow): void; isLayoutMonocleAndMinimizeRest(): boolean; showNotification(text: string): void; } @@ -93,7 +92,7 @@ export class TilingEngine implements Engine { * * Used when tile is resized using mouse. */ - public adjustLayout(basis: Window): void { + public adjustLayout(basis: EngineWindow): void { const srf = basis.surface; const layout = this.layouts.getCurrentLayout(srf); if (layout.adjust) { @@ -114,7 +113,7 @@ export class TilingEngine implements Engine { * @param window a floating window */ public resizeFloat( - window: Window, + window: EngineWindow, dir: "east" | "west" | "south" | "north", step: -1 | 1 ): void { @@ -153,7 +152,7 @@ export class TilingEngine implements Engine { * Used by grow/shrink shortcuts. */ public resizeTile( - basis: Window, + basis: EngineWindow, dir: "east" | "west" | "south" | "north", step: -1 | 1 ): void { @@ -220,14 +219,14 @@ export class TilingEngine implements Engine { * @param step which direction. 1 means outward, -1 means inward. */ public resizeWindow( - window: Window, + window: EngineWindow, dir: "east" | "west" | "south" | "north", step: -1 | 1 ): void { const state = window.state; - if (Window.isFloatingState(state)) { + if (EngineWindowImpl.isFloatingState(state)) { this.resizeFloat(window, dir, step); - } else if (Window.isTiledState(state)) { + } else if (EngineWindowImpl.isTiledState(state)) { this.resizeTile(window, dir, step); } } @@ -265,7 +264,7 @@ export class TilingEngine implements Engine { ]); // Set correct window state for new windows - visibleWindows.forEach((win: Window) => { + visibleWindows.forEach((win: EngineWindow) => { if (win.state === WindowState.Undecided) { win.state = win.shouldFloat ? WindowState.Floating : WindowState.Tiled; } @@ -303,7 +302,7 @@ export class TilingEngine implements Engine { } // Commit window assigned properties - visibleWindows.forEach((win: Window) => win.commit()); + visibleWindows.forEach((win: EngineWindow) => win.commit()); this.log.log(["arrangeScreen/finished", { screenSurface }]); } @@ -311,7 +310,7 @@ export class TilingEngine implements Engine { return this.layouts.getCurrentLayout(this.controller.currentSurface); } - public currentWindow(): Window | null { + public currentWindow(): EngineWindow | null { return this.controller.currentWindow; } @@ -322,7 +321,7 @@ export class TilingEngine implements Engine { * which is straight against the purpose of tiling WM. This operation * move/resize such windows back to where/how they should be. */ - public enforceSize(window: Window): void { + public enforceSize(window: EngineWindow): void { if (window.tiled && !window.actualGeometry.equals(window.geometry)) { window.commit(); } @@ -331,7 +330,7 @@ export class TilingEngine implements Engine { /** * Register the given window to WM. */ - public manage(window: Window): void { + public manage(window: EngineWindow): void { if (!window.shouldIgnore) { /* engine#arrange will update the state when required. */ window.state = WindowState.Undecided; @@ -346,7 +345,7 @@ export class TilingEngine implements Engine { /** * Unregister the given window from WM. */ - public unmanage(window: Window): void { + public unmanage(window: EngineWindow): void { this.windows.remove(window); } @@ -414,7 +413,7 @@ export class TilingEngine implements Engine { /** * Swap the position of the current window with the next or previous window. */ - public swapOrder(window: Window, step: -1 | 1): void { + public swapOrder(window: EngineWindow, step: -1 | 1): void { const srf = window.surface; const visibles = this.windows.getVisibleWindows(srf); if (visibles.length < 2) { @@ -455,7 +454,7 @@ export class TilingEngine implements Engine { * @param window a floating window * @param dir which direction */ - public moveFloat(window: Window, dir: Direction): void { + public moveFloat(window: EngineWindow, dir: Direction): void { const srf = window.surface; // TODO: configurable step size? @@ -492,9 +491,9 @@ export class TilingEngine implements Engine { } const state = window.state; - if (Window.isFloatingState(state)) { + if (EngineWindowImpl.isFloatingState(state)) { this.moveFloat(window, dir); - } else if (Window.isTiledState(state)) { + } else if (EngineWindowImpl.isTiledState(state)) { this.swapDirection(dir); } } @@ -502,7 +501,7 @@ export class TilingEngine implements Engine { /** * Toggle float mode of window. */ - public toggleFloat(window: Window): void { + public toggleFloat(window: EngineWindow): void { window.state = !window.tileable ? WindowState.Tiled : WindowState.Floating; } @@ -541,7 +540,7 @@ export class TilingEngine implements Engine { * Some layouts depend on this assumption, and will make such windows more * visible than others. */ - public setMaster(window: Window): void { + public setMaster(window: EngineWindow): void { this.windows.setMaster(window); } @@ -591,7 +590,7 @@ export class TilingEngine implements Engine { * Minimize all windows on the surface except the given window. * Used mainly in Monocle mode with config.monocleMinimizeRest */ - public minimizeOthers(window: Window): void { + public minimizeOthers(window: EngineWindow): void { for (const tile of this.windows.getVisibleTiles(window.surface)) { if ( tile.screen == window.screen && @@ -612,7 +611,10 @@ export class TilingEngine implements Engine { ); } - private getNeighborByDirection(basis: Window, dir: Direction): Window | null { + private getNeighborByDirection( + basis: EngineWindow, + dir: Direction + ): EngineWindow | null { let vertical: boolean; let sign: -1 | 1; switch (dir) { diff --git a/src/engine/layout/cascade_layout.ts b/src/engine/layout/cascade_layout.ts index 46dc1cfa..ad9dd6ed 100644 --- a/src/engine/layout/cascade_layout.ts +++ b/src/engine/layout/cascade_layout.ts @@ -6,8 +6,7 @@ import { WindowsLayout } from "."; import { Engine } from ".."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { Action, @@ -66,7 +65,11 @@ export default class CascadeLayout implements WindowsLayout { /* nothing */ } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { const [vertStep, horzStep] = CascadeLayout.decomposeDirection(this.dir); // TODO: adjustable step size diff --git a/src/engine/layout/floating_layout.ts b/src/engine/layout/floating_layout.ts index 20f5021e..ff794d61 100644 --- a/src/engine/layout/floating_layout.ts +++ b/src/engine/layout/floating_layout.ts @@ -5,8 +5,7 @@ import { WindowsLayout } from "."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import Rect from "../../util/rect"; import { Controller } from "../../controller"; @@ -20,11 +19,11 @@ export default class FloatingLayout implements WindowsLayout { public apply( _controller: Controller, - tileables: Window[], + tileables: EngineWindow[], _area: Rect ): void { tileables.forEach( - (tileable: Window) => (tileable.state = WindowState.TiledAfloat) + (tileable: EngineWindow) => (tileable.state = WindowState.TiledAfloat) ); } diff --git a/src/engine/layout/index.ts b/src/engine/layout/index.ts index 84577813..ab70981b 100644 --- a/src/engine/layout/index.ts +++ b/src/engine/layout/index.ts @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT -import Window from "../window"; +import { EngineWindow } from "../window"; import { Engine } from ".."; import { Controller } from "../../controller"; @@ -22,8 +22,13 @@ export interface WindowsLayout { readonly capacity?: number; readonly description: string; - adjust?(area: Rect, tiles: Window[], basis: Window, delta: RectDelta): void; - apply(controller: Controller, tileables: Window[], area: Rect): void; + adjust?( + area: Rect, + tiles: EngineWindow[], + basis: EngineWindow, + delta: RectDelta + ): void; + apply(controller: Controller, tileables: EngineWindow[], area: Rect): void; executeAction?(engine: Engine, action: Action): void; toString(): string; diff --git a/src/engine/layout/layout_part.ts b/src/engine/layout/layout_part.ts index d36e8078..c6f74e03 100644 --- a/src/engine/layout/layout_part.ts +++ b/src/engine/layout/layout_part.ts @@ -5,7 +5,7 @@ import LayoutUtils from "./layout_utils"; -import Window from "../window"; +import { EngineWindow } from "../window"; import Config from "../../config"; import Rect from "../../util/rect"; @@ -14,25 +14,25 @@ import RectDelta from "../../util/rectdelta"; export interface ILayoutPart { adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): RectDelta; - apply(area: Rect, tiles: Window[]): Rect[]; + apply(area: Rect, tiles: EngineWindow[]): Rect[]; } export class FillLayoutPart implements ILayoutPart { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): RectDelta { /* do nothing */ return delta; } - public apply(area: Rect, tiles: Window[]): Rect[] { + public apply(area: Rect, tiles: EngineWindow[]): Rect[] { return tiles.map((_tile) => { return area; }); @@ -74,8 +74,8 @@ export class HalfSplitLayoutPart public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): RectDelta { const basisIndex = tiles.indexOf(basis); @@ -141,7 +141,7 @@ export class HalfSplitLayoutPart } } - public apply(area: Rect, tiles: Window[]): Rect[] { + public apply(area: Rect, tiles: EngineWindow[]): Rect[] { if (tiles.length <= this.primarySize) { /* primary only */ return this.primary.apply(area, tiles); @@ -183,8 +183,8 @@ export class StackLayoutPart implements ILayoutPart { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): RectDelta { const weights = LayoutUtils.adjustAreaWeights( @@ -209,7 +209,7 @@ export class StackLayoutPart implements ILayoutPart { ); } - public apply(area: Rect, tiles: Window[]): Rect[] { + public apply(area: Rect, tiles: EngineWindow[]): Rect[] { const weights = tiles.map((tile) => tile.weight); return LayoutUtils.splitAreaWeighted(area, weights, this.gap); } @@ -220,8 +220,8 @@ export class RotateLayoutPart implements ILayoutPart { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): RectDelta { // let area = area, delta = delta; @@ -260,7 +260,7 @@ export class RotateLayoutPart implements ILayoutPart { return delta; } - public apply(area: Rect, tiles: Window[]): Rect[] { + public apply(area: Rect, tiles: EngineWindow[]): Rect[] { switch (this.angle) { case 0: break; diff --git a/src/engine/layout/monocle_layout.ts b/src/engine/layout/monocle_layout.ts index 90a5b0ba..6235c647 100644 --- a/src/engine/layout/monocle_layout.ts +++ b/src/engine/layout/monocle_layout.ts @@ -5,8 +5,7 @@ import { WindowsLayout } from "."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { Action, @@ -35,7 +34,11 @@ export default class MonocleLayout implements WindowsLayout { this.config = config; } - public apply(controller: Controller, tileables: Window[], area: Rect): void { + public apply( + controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { /* Tile all tileables */ tileables.forEach((tile) => { tile.state = this.config.monocleMaximize diff --git a/src/engine/layout/quarter_layout.ts b/src/engine/layout/quarter_layout.ts index 61568ce1..1012daf6 100644 --- a/src/engine/layout/quarter_layout.ts +++ b/src/engine/layout/quarter_layout.ts @@ -5,8 +5,7 @@ import { WindowsLayout } from "."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { clip } from "../../util/func"; import Rect from "../../util/rect"; @@ -41,8 +40,8 @@ export default class QuarterLayout implements WindowsLayout { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): void { if (tiles.length <= 1 || tiles.length > 4) { @@ -113,7 +112,11 @@ export default class QuarterLayout implements WindowsLayout { return other; } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { for (let i = 0; i < 4 && i < tileables.length; i++) { tileables[i].state = WindowState.Tiled; } diff --git a/src/engine/layout/spiral_layout.ts b/src/engine/layout/spiral_layout.ts index bbccd8e7..aeba0e45 100644 --- a/src/engine/layout/spiral_layout.ts +++ b/src/engine/layout/spiral_layout.ts @@ -7,8 +7,7 @@ import { HalfSplitLayoutPart } from "./layout_part"; import { FillLayoutPart } from "./layout_part"; import { WindowsLayout } from "."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import Rect from "../../util/rect"; import RectDelta from "../../util/rectdelta"; @@ -42,14 +41,18 @@ export default class SpiralLayout implements WindowsLayout { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): void { this.parts.adjust(area, tiles, basis, delta); } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); this.bore(tileables.length); diff --git a/src/engine/layout/spread_layout.ts b/src/engine/layout/spread_layout.ts index c6c4fe80..c9809ced 100644 --- a/src/engine/layout/spread_layout.ts +++ b/src/engine/layout/spread_layout.ts @@ -5,8 +5,7 @@ import { WindowsLayout } from "."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { Action, @@ -30,7 +29,11 @@ export default class SpreadLayout implements WindowsLayout { this.space = 0.07; } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { /* Tile all tileables */ tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); const tiles = tileables; diff --git a/src/engine/layout/stair_layout.ts b/src/engine/layout/stair_layout.ts index 2fb164ad..1cfeb504 100644 --- a/src/engine/layout/stair_layout.ts +++ b/src/engine/layout/stair_layout.ts @@ -5,8 +5,7 @@ import { WindowsLayout } from "."; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { Action, @@ -30,7 +29,11 @@ export default class StairLayout implements WindowsLayout { this.space = 24; } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { /* Tile all tileables */ tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); const tiles = tileables; diff --git a/src/engine/layout/three_column_layout.ts b/src/engine/layout/three_column_layout.ts index 28958672..48eb53f8 100644 --- a/src/engine/layout/three_column_layout.ts +++ b/src/engine/layout/three_column_layout.ts @@ -6,8 +6,7 @@ import { WindowsLayout } from "."; import LayoutUtils from "./layout_utils"; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { Action, @@ -48,8 +47,8 @@ export default class ThreeColumnLayout implements WindowsLayout { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): void { const basisIndex = tiles.indexOf(basis); @@ -128,7 +127,10 @@ export default class ThreeColumnLayout implements WindowsLayout { /* adjust tile weight */ const rstackNumTile = Math.floor((tiles.length - this.masterSize) / 2); const [masterTiles, rstackTiles, lstackTiles] = - partitionArrayBySizes(tiles, [this.masterSize, rstackNumTile]); + partitionArrayBySizes(tiles, [ + this.masterSize, + rstackNumTile, + ]); const groupTiles = [lstackTiles, masterTiles, rstackTiles][basisGroup]; LayoutUtils.adjustAreaWeights( area /* we only need height */, @@ -142,7 +144,11 @@ export default class ThreeColumnLayout implements WindowsLayout { } } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { /* Tile all tileables */ tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); const tiles = tileables; @@ -185,7 +191,10 @@ export default class ThreeColumnLayout implements WindowsLayout { const rstackSize = Math.floor((tiles.length - this.masterSize) / 2); const [masterTiles, rstackTiles, lstackTiles] = - partitionArrayBySizes(tiles, [this.masterSize, rstackSize]); + partitionArrayBySizes(tiles, [ + this.masterSize, + rstackSize, + ]); [lstackTiles, masterTiles, rstackTiles].forEach((groupTiles, group) => { LayoutUtils.splitAreaWeighted( groupAreas[group], diff --git a/src/engine/layout/tile_layout.ts b/src/engine/layout/tile_layout.ts index bb4ddb24..cab97676 100644 --- a/src/engine/layout/tile_layout.ts +++ b/src/engine/layout/tile_layout.ts @@ -10,8 +10,7 @@ import { StackLayoutPart, } from "./layout_part"; -import Window from "../window"; -import { WindowState } from "../window"; +import { WindowState, EngineWindow } from "../window"; import { Action, @@ -82,14 +81,18 @@ export default class TileLayout implements WindowsLayout { public adjust( area: Rect, - tiles: Window[], - basis: Window, + tiles: EngineWindow[], + basis: EngineWindow, delta: RectDelta ): void { this.parts.adjust(area, tiles, basis, delta); } - public apply(_controller: Controller, tileables: Window[], area: Rect): void { + public apply( + _controller: Controller, + tileables: EngineWindow[], + area: Rect + ): void { tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); this.parts.apply(area, tileables).forEach((geometry, i) => { diff --git a/src/engine/window.ts b/src/engine/window.ts index 13244589..3f356b18 100644 --- a/src/engine/window.ts +++ b/src/engine/window.ts @@ -12,14 +12,20 @@ import Rect from "../util/rect"; import RectDelta from "../util/rectdelta"; export enum WindowState { - /* initial value */ + /** + * Initial value + */ Unmanaged, - /* script-external state - overrides internal state */ + /** + * Script-external state - overrides internal state + */ NativeFullscreen, NativeMaximized, - /* script-internal state */ + /** + * Script-internal state + */ Floating, Maximized, Tiled, @@ -27,7 +33,135 @@ export enum WindowState { Undecided, } -export default class Window { +/** + * Window with the convenient for the Engine Interface + */ +export interface EngineWindow { + /** + * Window unique id + */ + readonly id: string; + + /** + * If this window ***can be*** tiled by layout. + */ + readonly tileable: boolean; + + /** + * If this window is ***already*** tiled, thus a part of the current layout. + */ + readonly tiled: boolean; + + /** + * If this window is floating, thus its geometry is not tightly managed. + */ + readonly floating: boolean; + + /** + * Whether the window is shaded (collapsed to the title bar) + */ + readonly shaded: boolean; + + /** + * Low-level implementation, usable for Driver + */ + readonly window: DriverWindow; + + /** + * Difference between geometry and actual geometry + */ + readonly geometryDelta: RectDelta; + + /** + * Actual geometry + */ + readonly actualGeometry: Readonly; + + /** + * Whether the window is a dialog window + */ + readonly isDialog: boolean; + + /** + * Whether the window should be set to floating state + */ + readonly shouldFloat: boolean; + + /** + * Whether the window should be ignored by the script + */ + readonly shouldIgnore: boolean; + + /** + * State to which the window was asked to be changed + * previously. This can be the same state, as the current + * one. + */ + readonly statePreviouslyAskedToChangeTo: WindowState; + + /** + * Screen number, on which the window is present + */ + readonly screen: number; + + /** + * Whether the window is minimized + */ + minimized: boolean; + + /** + * Geometry of a window, while in floated state + */ + floatGeometry: Rect; + + /** + * Window geometry + */ + geometry: Rect; + + /** + * Surface, the window is currently on + */ + surface: DriverSurface; + + /** + * General state of the window: floating, maximized, tiled etc. + */ + state: WindowState; + + /** + * The timestamp when the last time Window was focused. + */ + timestamp: number; + + /** + * Window weight. + * TODO: This needs a better explanation. This has something to do with ThreeColumnLayout. + */ + weight: number; + + /** + * Whether the window is visible on concrete surface + * @param surface the surface visibility on which is checked + */ + visible(surface: DriverSurface): boolean; + + /** + * Force apply the geometry *immediately*. + * + * This method is a quick hack created for engine#resizeFloat, thus should + * not be used in other places. + */ + forceSetGeometry(geometry: Rect): void; + + /** + * Update changed window properties on the KWin side. + * I.e. make the changes visible to the end user. + */ + commit(): void; +} + +export class EngineWindowImpl implements EngineWindow { public static isTileableState(state: WindowState): boolean { return ( state === WindowState.Tiled || @@ -69,17 +203,16 @@ export default class Window { this.window.minimized = min; } - /** If this window ***can be*** tiled by layout. */ public get tileable(): boolean { - return Window.isTileableState(this.state); + return EngineWindowImpl.isTileableState(this.state); } - /** If this window is ***already*** tiled, thus a part of the current layout. */ + public get tiled(): boolean { - return Window.isTiledState(this.state); + return EngineWindowImpl.isTiledState(this.state); } - /** If this window is floating, thus its geometry is not tightly managed. */ + public get floating(): boolean { - return Window.isFloatingState(this.state); + return EngineWindowImpl.isFloatingState(this.state); } public get geometryDelta(): RectDelta { @@ -125,13 +258,13 @@ export default class Window { if ( (winState === WindowState.Unmanaged || - Window.isTileableState(winState)) && - Window.isFloatingState(value) + EngineWindowImpl.isTileableState(winState)) && + EngineWindowImpl.isFloatingState(value) ) { this.shouldCommitFloat = true; } else if ( - Window.isFloatingState(winState) && - Window.isTileableState(value) + EngineWindowImpl.isFloatingState(winState) && + EngineWindowImpl.isTileableState(value) ) { /* save the current geometry before leaving floating state */ this.floatGeometry = this.actualGeometry; @@ -167,6 +300,10 @@ export default class Window { this.weightMap[srfID] = value; } + public get isDialog(): boolean { + return this.window.isDialog; + } + private internalState: WindowState; private internalStatePreviouslyAskedToChangeTo: WindowState; private shouldCommitFloat: boolean; @@ -236,12 +373,6 @@ export default class Window { } } - /** - * Force apply the geometry *immediately*. - * - * This method is a quick hack created for engine#resizeFloat, thus should - * not be used in other places. - */ public forceSetGeometry(geometry: Rect): void { this.window.commit(geometry); } diff --git a/src/engine/window_store.ts b/src/engine/window_store.ts index 187caaad..a5931705 100644 --- a/src/engine/window_store.ts +++ b/src/engine/window_store.ts @@ -3,18 +3,22 @@ // // SPDX-License-Identifier: MIT -import Window from "./window"; +import { EngineWindow } from "./window"; import { DriverSurface } from "../driver/surface"; export default class WindowStore { - public list: Window[]; + public list: EngineWindow[]; - constructor(windows?: Window[]) { + constructor(windows?: EngineWindow[]) { this.list = windows || []; } - public move(srcWin: Window, destWin: Window, after?: boolean): void { + public move( + srcWin: EngineWindow, + destWin: EngineWindow, + after?: boolean + ): void { const srcIdx = this.list.indexOf(srcWin); const destIdx = this.list.indexOf(destWin); if (srcIdx === -1 || destIdx === -1) { @@ -25,7 +29,7 @@ export default class WindowStore { this.list.splice(after ? destIdx + 1 : destIdx, 0, srcWin); } - public setMaster(window: Window): void { + public setMaster(window: EngineWindow): void { const idx = this.list.indexOf(window); if (idx === -1) { return; @@ -34,7 +38,7 @@ export default class WindowStore { this.list.splice(0, 0, window); } - public swap(alpha: Window, beta: Window): void { + public swap(alpha: EngineWindow, beta: EngineWindow): void { const alphaIndex = this.list.indexOf(alpha); const betaIndex = this.list.indexOf(beta); if (alphaIndex < 0 || betaIndex < 0) { @@ -51,26 +55,26 @@ export default class WindowStore { return this.list.length; } - public at(idx: number): Window { + public at(idx: number): EngineWindow { return this.list[idx]; } - public indexOf(window: Window): number { + public indexOf(window: EngineWindow): number { return this.list.indexOf(window); } - public push(window: Window): void { + public push(window: EngineWindow): void { this.list.push(window); } - public remove(window: Window): void { + public remove(window: EngineWindow): void { const idx = this.list.indexOf(window); if (idx >= 0) { this.list.splice(idx, 1); } } - public unshift(window: Window): void { + public unshift(window: EngineWindow): void { this.list.unshift(window); } //#endregion @@ -78,12 +82,12 @@ export default class WindowStore { //#region Querying Windows /** Returns all visible windows on the given surface. */ - public getVisibleWindows(srf: DriverSurface): Window[] { + public getVisibleWindows(srf: DriverSurface): EngineWindow[] { return this.list.filter((win) => win.visible(srf)); } /** Return all visible "Tile" windows on the given surface. */ - public getVisibleTiles(srf: DriverSurface): Window[] { + public getVisibleTiles(srf: DriverSurface): EngineWindow[] { return this.list.filter((win) => win.tiled && win.visible(srf)); } @@ -91,19 +95,19 @@ export default class WindowStore { * Return all visible "tileable" windows on the given surface * @see Window#tileable */ - public getVisibleTileables(srf: DriverSurface): Window[] { + public getVisibleTileables(srf: DriverSurface): EngineWindow[] { return this.list.filter((win) => win.tileable && win.visible(srf)); } /** * Return all "tileable" windows on the given surface, including hidden */ - public getAllTileables(srf: DriverSurface): Window[] { + public getAllTileables(srf: DriverSurface): EngineWindow[] { return this.list.filter((win) => win.tileable && win.surface.id === srf.id); } /** Return all windows on this surface, including minimized windows */ - public getAllWindows(srf: DriverSurface): Window[] { + public getAllWindows(srf: DriverSurface): EngineWindow[] { return this.list.filter((win) => win.surface.id === srf.id); }