refactor: split engine window to interface

This commit is contained in:
Mikhail Zolotukhin 2021-10-19 00:04:36 +03:00
parent 26280306fb
commit bf4244562d
18 changed files with 353 additions and 179 deletions

View File

@ -7,7 +7,7 @@
import { createMock } from "ts-auto-mock"; import { createMock } from "ts-auto-mock";
import { Engine } from "../engine"; import { Engine } from "../engine";
import { WindowsLayout } from "../engine/layout"; import { WindowsLayout } from "../engine/layout";
import Window from "../engine/window"; import { EngineWindow } from "../engine/window";
import { NullLog } from "../util/log"; import { NullLog } from "../util/log";
import * as Action from "./action"; import * as Action from "./action";
@ -89,9 +89,9 @@ describe("action", () => {
describe("move window", () => { describe("move window", () => {
let fakeEngine: Engine; let fakeEngine: Engine;
let fakeCurrentWindow: Window; let fakeCurrentWindow: EngineWindow;
beforeEach(() => { beforeEach(() => {
fakeCurrentWindow = createMock<Window>(); fakeCurrentWindow = createMock<EngineWindow>();
fakeEngine = createMock<Engine>({ fakeEngine = createMock<Engine>({
swapOrder: jest.fn(), swapOrder: jest.fn(),
@ -169,10 +169,10 @@ describe("action", () => {
describe("window resize", () => { describe("window resize", () => {
let fakeEngine: Engine; let fakeEngine: Engine;
let fakeCurrentWindow: Window; let fakeCurrentWindow: EngineWindow;
beforeEach(() => { beforeEach(() => {
fakeCurrentWindow = createMock<Window>(); fakeCurrentWindow = createMock<EngineWindow>();
fakeEngine = createMock<Engine>({ fakeEngine = createMock<Engine>({
resizeWindow: jest.fn(), resizeWindow: jest.fn(),
@ -313,7 +313,7 @@ describe("action", () => {
describe("toggle floating", () => { describe("toggle floating", () => {
it("executes correctly", () => { it("executes correctly", () => {
const fakeCurrentWindow = createMock<Window>(); const fakeCurrentWindow = createMock<EngineWindow>();
const fakeEngine = createMock<Engine>({ const fakeEngine = createMock<Engine>({
toggleFloat: jest.fn(), toggleFloat: jest.fn(),
currentWindow: jest.fn().mockReturnValue(fakeCurrentWindow), currentWindow: jest.fn().mockReturnValue(fakeCurrentWindow),
@ -329,7 +329,7 @@ describe("action", () => {
describe("push window into master area", () => { describe("push window into master area", () => {
it("executes correctly", () => { it("executes correctly", () => {
const fakeCurrentWindow = createMock<Window>(); const fakeCurrentWindow = createMock<EngineWindow>();
const fakeEngine = createMock<Engine>({ const fakeEngine = createMock<Engine>({
setMaster: jest.fn(), setMaster: jest.fn(),
currentWindow: jest.fn().mockReturnValue(fakeCurrentWindow), currentWindow: jest.fn().mockReturnValue(fakeCurrentWindow),
@ -348,10 +348,10 @@ describe("action", () => {
describe("layout switching", () => { describe("layout switching", () => {
let fakeEngine: Engine; let fakeEngine: Engine;
let fakeCurrentWindow: Window; let fakeCurrentWindow: EngineWindow;
beforeEach(() => { beforeEach(() => {
fakeCurrentWindow = createMock<Window>(); fakeCurrentWindow = createMock<EngineWindow>();
fakeEngine = createMock<Engine>({ fakeEngine = createMock<Engine>({
cycleLayout: jest.fn(), cycleLayout: jest.fn(),

View File

@ -4,7 +4,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { Engine, TilingEngine } from "../engine"; import { Engine, TilingEngine } from "../engine";
import Window from "../engine/window"; import { EngineWindow } from "../engine/window";
import { WindowState } from "../engine/window"; import { WindowState } from "../engine/window";
import { DriverContext, KWinDriver } from "../driver"; import { DriverContext, KWinDriver } from "../driver";
@ -31,7 +31,7 @@ export interface Controller {
/** /**
* Current active window. In other words the window, that has focus. * 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. * Current screen. In other words the screen, that has focus.
@ -59,13 +59,13 @@ export interface Controller {
* React to window geometry update * React to window geometry update
* @param window the window whose geometry has changed * @param window the window whose geometry has changed
*/ */
onWindowGeometryChanged(window: Window): void; onWindowGeometryChanged(window: EngineWindow): void;
/** /**
* React to window resizing * React to window resizing
* @param window the window which is resized * @param window the window which is resized
*/ */
onWindowResize(window: Window): void; onWindowResize(window: EngineWindow): void;
/** /**
* React to window resize operation start. The window * React to window resize operation start. The window
@ -73,7 +73,7 @@ export interface Controller {
* the window with the mouse by the window edges. * the window with the mouse by the window edges.
* @param window the window which is being resized * @param window the window which is being resized
*/ */
onWindowResizeStart(window: Window): void; onWindowResizeStart(window: EngineWindow): void;
/** /**
* React to window resize operation end. The window * React to window resize operation end. The window
@ -81,35 +81,35 @@ export interface Controller {
* the window. * the window.
* @param window the window which was dropped * @param window the window which was dropped
*/ */
onWindowResizeOver(window: Window): void; onWindowResizeOver(window: EngineWindow): void;
/** /**
* React to window addition * React to window addition
* @param window new added window * @param window new added window
*/ */
onWindowAdded(window: Window): void; onWindowAdded(window: EngineWindow): void;
/** /**
* React to window removal * React to window removal
* @param window the window which was removed * @param window the window which was removed
*/ */
onWindowRemoved(window: Window): void; onWindowRemoved(window: EngineWindow): void;
/** /**
* React to window maximization state change * React to window maximization state change
* @param window the window whose maximization state changed * @param window the window whose maximization state changed
* @param maximized new maximization state * @param maximized new maximization state
*/ */
onWindowMaximizeChanged(window: Window, maximized: boolean): void; onWindowMaximizeChanged(window: EngineWindow, maximized: boolean): void;
// TODO: add docs // TODO: add docs
onWindowChanged(window: Window | null, comment?: string): void; onWindowChanged(window: EngineWindow | null, comment?: string): void;
/** /**
* React to window being moved. * React to window being moved.
* @param window the window, which it 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 * React to window move operation start. The move operation starts
@ -117,7 +117,7 @@ export interface Controller {
* the mouse's button being pressed * the mouse's button being pressed
* @param window the window which is being dragged * @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 * React to window move operation over. The move operation ends
@ -125,25 +125,25 @@ export interface Controller {
* the mouse's button being released. * the mouse's button being released.
* @param window the window which was being dragged * @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 * React to the window gaining focus, attention and love it deserves
* @param window the window which received the focus * @param window the window which received the focus
*/ */
onWindowFocused(window: Window): void; onWindowFocused(window: EngineWindow): void;
/** /**
* React to the window shade state change * React to the window shade state change
* @param window the window whose state was changed * @param window the window whose state was changed
*/ */
onWindowShadeChanged(window: Window): void; onWindowShadeChanged(window: EngineWindow): void;
/** /**
* Ask engine to manage the window * Ask engine to manage the window
* @param win the window which needs to be managed. * @param win the window which needs to be managed.
*/ */
manageWindow(win: Window): void; manageWindow(win: EngineWindow): void;
} }
export class TilingController implements Controller { export class TilingController implements Controller {
@ -178,11 +178,11 @@ export class TilingController implements Controller {
return this.driver.screens; return this.driver.screens;
} }
public get currentWindow(): Window | null { public get currentWindow(): EngineWindow | null {
return this.driver.currentWindow; return this.driver.currentWindow;
} }
public set currentWindow(value: Window | null) { public set currentWindow(value: EngineWindow | null) {
this.driver.currentWindow = value; 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.log.log(["onWindowAdded", { window }]);
this.engine.manage(window); this.engine.manage(window);
@ -236,7 +236,7 @@ export class TilingController implements Controller {
this.engine.arrange(); this.engine.arrange();
} }
public onWindowRemoved(window: Window): void { public onWindowRemoved(window: EngineWindow): void {
this.log.log(["onWindowRemoved", { window }]); this.log.log(["onWindowRemoved", { window }]);
this.engine.unmanage(window); this.engine.unmanage(window);
@ -244,7 +244,7 @@ export class TilingController implements Controller {
// Switch to next window if monocle with config.monocleMinimizeRest // Switch to next window if monocle with config.monocleMinimizeRest
if ( if (
!window.window.isDialog && !window.isDialog &&
!this.currentWindow && !this.currentWindow &&
this.engine.isLayoutMonocleAndMinimizeRest() this.engine.isLayoutMonocleAndMinimizeRest()
) { ) {
@ -257,15 +257,15 @@ export class TilingController implements Controller {
} }
} }
public onWindowMoveStart(_window: Window): void { public onWindowMoveStart(_window: EngineWindow): void {
/* do nothing */ /* do nothing */
} }
public onWindowMove(_window: Window): void { public onWindowMove(_window: EngineWindow): void {
/* do nothing */ /* do nothing */
} }
public onWindowMoveOver(window: Window): void { public onWindowMoveOver(window: EngineWindow): void {
this.log.log(["onWindowMoveOver", { window }]); this.log.log(["onWindowMoveOver", { window }]);
/* swap window by dragging */ /* swap window by dragging */
@ -302,11 +302,11 @@ export class TilingController implements Controller {
window.commit(); window.commit();
} }
public onWindowResizeStart(_window: Window): void { public onWindowResizeStart(_window: EngineWindow): void {
/* do nothing */ /* do nothing */
} }
public onWindowResize(window: Window): void { public onWindowResize(window: EngineWindow): void {
this.log.log(["onWindowResize", { window }]); this.log.log(["onWindowResize", { window }]);
if (this.config.adjustLayout && this.config.adjustLayoutLive) { if (this.config.adjustLayout && this.config.adjustLayoutLive) {
if (window.state === WindowState.Tiled) { 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 }]); this.log.log(["onWindowResizeOver", { window }]);
if (this.config.adjustLayout && window.tiled) { if (this.config.adjustLayout && window.tiled) {
this.engine.adjustLayout(window); 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(); this.engine.arrange();
} }
public onWindowGeometryChanged(window: Window): void { public onWindowGeometryChanged(window: EngineWindow): void {
this.log.log(["onWindowGeometryChanged", { window }]); this.log.log(["onWindowGeometryChanged", { window }]);
this.engine.enforceSize(window); this.engine.enforceSize(window);
} }
// NOTE: accepts `null` to simplify caller. This event is a catch-all hack // NOTE: accepts `null` to simplify caller. This event is a catch-all hack
// by itself anyway. // by itself anyway.
public onWindowChanged(window: Window | null, comment?: string): void { public onWindowChanged(window: EngineWindow | null, comment?: string): void {
if (window) { if (window) {
this.log.log(["onWindowChanged", { window, comment }]); 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 { try {
window.timestamp = new Date().getTime(); window.timestamp = new Date().getTime();
this.currentWindow = window; 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}`); this.log.log(`onWindowShadeChanged, window: ${win}`);
// NOTE: Float shaded windows and change their state back once unshaded // NOTE: Float shaded windows and change their state back once unshaded
@ -391,7 +394,7 @@ export class TilingController implements Controller {
this.engine.arrange(); this.engine.arrange();
} }
public manageWindow(win: Window): void { public manageWindow(win: EngineWindow): void {
this.engine.manage(win); this.engine.manage(win);
} }

View File

@ -10,7 +10,7 @@ import { KWinWindow } from "./window";
import { Controller } from "../controller"; import { Controller } from "../controller";
import { Action } from "../controller/action"; import { Action } from "../controller/action";
import Window from "../engine/window"; import { EngineWindow, EngineWindowImpl } from "../engine/window";
import { WindowState } from "../engine/window"; import { WindowState } from "../engine/window";
@ -21,7 +21,7 @@ export interface DriverContext {
readonly screens: DriverSurface[]; readonly screens: DriverSurface[];
currentSurface: DriverSurface; currentSurface: DriverSurface;
currentWindow: Window | null; currentWindow: EngineWindow | null;
showNotification(text: string): void; 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; const client = this.kwinApi.workspace.activeClient;
return client ? this.windowMap.get(client) : null; return client ? this.windowMap.get(client) : null;
} }
public set currentWindow(window: Window | null) { public set currentWindow(window: EngineWindow | null) {
if (window !== null) { if (window !== null) {
this.kwinApi.workspace.activeClient = ( this.kwinApi.workspace.activeClient = (
window.window as KWinWindow window.window as KWinWindow
@ -94,7 +94,7 @@ export class KWinDriver implements DriverContext {
} }
private controller: Controller; private controller: Controller;
private windowMap: WrapperMap<KWin.Client, Window>; private windowMap: WrapperMap<KWin.Client, EngineWindow>;
private entered: boolean; private entered: boolean;
private qml: Bismuth.Qml.Main; private qml: Bismuth.Qml.Main;
@ -126,7 +126,7 @@ export class KWinDriver implements DriverContext {
this.windowMap = new WrapperMap( this.windowMap = new WrapperMap(
(client: KWin.Client) => KWinWindow.generateID(client), (client: KWin.Client) => KWinWindow.generateID(client),
(client: KWin.Client) => (client: KWin.Client) =>
new Window( new EngineWindowImpl(
new KWinWindow(client, this.qml, this.kwinApi, this.config, this.log), new KWinWindow(client, this.qml, this.kwinApi, this.config, this.log),
this.config, this.config,
this.log 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 moving = false;
let resizing = false; let resizing = false;

View File

@ -15,7 +15,7 @@ import { Log } from "../util/log";
import Rect from "../util/rect"; import Rect from "../util/rect";
import TileLayout from "./layout/tile_layout"; import TileLayout from "./layout/tile_layout";
import LayoutStore from "./layout_store"; import LayoutStore from "./layout_store";
import Window, { WindowState } from "./window"; import { EngineWindow, WindowState } from "./window";
import WindowStore from "./window_store"; import WindowStore from "./window_store";
describe("arrange", () => { describe("arrange", () => {
@ -47,12 +47,12 @@ describe("arrangeScreen", () => {
const configMock = createMock<Config>(); const configMock = createMock<Config>();
const engine = new TilingEngine(controllerMock, configMock, logMock); const engine = new TilingEngine(controllerMock, configMock, logMock);
const window1 = createMock<Window>({ const window1 = createMock<EngineWindow>({
shouldFloat: false, shouldFloat: false,
state: WindowState.Undecided, state: WindowState.Undecided,
}); });
const window2 = createMock<Window>({ const window2 = createMock<EngineWindow>({
shouldFloat: true, shouldFloat: true,
state: WindowState.Undecided, state: WindowState.Undecided,
}); });

View File

@ -7,8 +7,7 @@ import MonocleLayout from "./layout/monocle_layout";
import LayoutStore from "./layout_store"; import LayoutStore from "./layout_store";
import WindowStore from "./window_store"; import WindowStore from "./window_store";
import Window from "./window"; import { EngineWindow, EngineWindowImpl, WindowState } from "./window";
import { WindowState } from "./window";
import { Controller } from "../controller"; import { Controller } from "../controller";
@ -28,27 +27,27 @@ export interface Engine {
windows: WindowStore; windows: WindowStore;
arrange(): void; arrange(): void;
manage(window: Window): void; manage(window: EngineWindow): void;
unmanage(window: Window): void; unmanage(window: EngineWindow): void;
adjustLayout(basis: Window): void; adjustLayout(basis: EngineWindow): void;
resizeFloat( resizeFloat(
window: Window, window: EngineWindow,
dir: "east" | "west" | "south" | "north", dir: "east" | "west" | "south" | "north",
step: -1 | 1 step: -1 | 1
): void; ): void;
resizeTile( resizeTile(
basis: Window, basis: EngineWindow,
dir: "east" | "west" | "south" | "north", dir: "east" | "west" | "south" | "north",
step: -1 | 1 step: -1 | 1
): void; ): void;
resizeWindow( resizeWindow(
window: Window, window: EngineWindow,
dir: "east" | "west" | "south" | "north", dir: "east" | "west" | "south" | "north",
step: -1 | 1 step: -1 | 1
): void; ): void;
enforceSize(window: Window): void; enforceSize(window: EngineWindow): void;
currentLayoutOnCurrentSurface(): WindowsLayout; currentLayoutOnCurrentSurface(): WindowsLayout;
currentWindow(): Window | null; currentWindow(): EngineWindow | null;
/** /**
* Focus next or previous window * Focus next or previous window
@ -57,14 +56,14 @@ export interface Engine {
*/ */
focusOrder(step: -1 | 1, includeHidden: boolean): void; focusOrder(step: -1 | 1, includeHidden: boolean): void;
focusDir(dir: Direction): void; focusDir(dir: Direction): void;
swapOrder(window: Window, step: -1 | 1): void; swapOrder(window: EngineWindow, step: -1 | 1): void;
swapDirOrMoveFloat(dir: Direction): void; swapDirOrMoveFloat(dir: Direction): void;
setMaster(window: Window): void; setMaster(window: EngineWindow): void;
toggleFloat(window: Window): void; toggleFloat(window: EngineWindow): void;
floatAll(srf: DriverSurface): void; floatAll(srf: DriverSurface): void;
cycleLayout(step: 1 | -1): void; cycleLayout(step: 1 | -1): void;
setLayout(layoutClassID: string): void; setLayout(layoutClassID: string): void;
minimizeOthers(window: Window): void; minimizeOthers(window: EngineWindow): void;
isLayoutMonocleAndMinimizeRest(): boolean; isLayoutMonocleAndMinimizeRest(): boolean;
showNotification(text: string): void; showNotification(text: string): void;
} }
@ -93,7 +92,7 @@ export class TilingEngine implements Engine {
* *
* Used when tile is resized using mouse. * Used when tile is resized using mouse.
*/ */
public adjustLayout(basis: Window): void { public adjustLayout(basis: EngineWindow): void {
const srf = basis.surface; const srf = basis.surface;
const layout = this.layouts.getCurrentLayout(srf); const layout = this.layouts.getCurrentLayout(srf);
if (layout.adjust) { if (layout.adjust) {
@ -114,7 +113,7 @@ export class TilingEngine implements Engine {
* @param window a floating window * @param window a floating window
*/ */
public resizeFloat( public resizeFloat(
window: Window, window: EngineWindow,
dir: "east" | "west" | "south" | "north", dir: "east" | "west" | "south" | "north",
step: -1 | 1 step: -1 | 1
): void { ): void {
@ -153,7 +152,7 @@ export class TilingEngine implements Engine {
* Used by grow/shrink shortcuts. * Used by grow/shrink shortcuts.
*/ */
public resizeTile( public resizeTile(
basis: Window, basis: EngineWindow,
dir: "east" | "west" | "south" | "north", dir: "east" | "west" | "south" | "north",
step: -1 | 1 step: -1 | 1
): void { ): void {
@ -220,14 +219,14 @@ export class TilingEngine implements Engine {
* @param step which direction. 1 means outward, -1 means inward. * @param step which direction. 1 means outward, -1 means inward.
*/ */
public resizeWindow( public resizeWindow(
window: Window, window: EngineWindow,
dir: "east" | "west" | "south" | "north", dir: "east" | "west" | "south" | "north",
step: -1 | 1 step: -1 | 1
): void { ): void {
const state = window.state; const state = window.state;
if (Window.isFloatingState(state)) { if (EngineWindowImpl.isFloatingState(state)) {
this.resizeFloat(window, dir, step); this.resizeFloat(window, dir, step);
} else if (Window.isTiledState(state)) { } else if (EngineWindowImpl.isTiledState(state)) {
this.resizeTile(window, dir, step); this.resizeTile(window, dir, step);
} }
} }
@ -265,7 +264,7 @@ export class TilingEngine implements Engine {
]); ]);
// Set correct window state for new windows // Set correct window state for new windows
visibleWindows.forEach((win: Window) => { visibleWindows.forEach((win: EngineWindow) => {
if (win.state === WindowState.Undecided) { if (win.state === WindowState.Undecided) {
win.state = win.shouldFloat ? WindowState.Floating : WindowState.Tiled; win.state = win.shouldFloat ? WindowState.Floating : WindowState.Tiled;
} }
@ -303,7 +302,7 @@ export class TilingEngine implements Engine {
} }
// Commit window assigned properties // Commit window assigned properties
visibleWindows.forEach((win: Window) => win.commit()); visibleWindows.forEach((win: EngineWindow) => win.commit());
this.log.log(["arrangeScreen/finished", { screenSurface }]); this.log.log(["arrangeScreen/finished", { screenSurface }]);
} }
@ -311,7 +310,7 @@ export class TilingEngine implements Engine {
return this.layouts.getCurrentLayout(this.controller.currentSurface); return this.layouts.getCurrentLayout(this.controller.currentSurface);
} }
public currentWindow(): Window | null { public currentWindow(): EngineWindow | null {
return this.controller.currentWindow; return this.controller.currentWindow;
} }
@ -322,7 +321,7 @@ export class TilingEngine implements Engine {
* which is straight against the purpose of tiling WM. This operation * which is straight against the purpose of tiling WM. This operation
* move/resize such windows back to where/how they should be. * 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)) { if (window.tiled && !window.actualGeometry.equals(window.geometry)) {
window.commit(); window.commit();
} }
@ -331,7 +330,7 @@ export class TilingEngine implements Engine {
/** /**
* Register the given window to WM. * Register the given window to WM.
*/ */
public manage(window: Window): void { public manage(window: EngineWindow): void {
if (!window.shouldIgnore) { if (!window.shouldIgnore) {
/* engine#arrange will update the state when required. */ /* engine#arrange will update the state when required. */
window.state = WindowState.Undecided; window.state = WindowState.Undecided;
@ -346,7 +345,7 @@ export class TilingEngine implements Engine {
/** /**
* Unregister the given window from WM. * Unregister the given window from WM.
*/ */
public unmanage(window: Window): void { public unmanage(window: EngineWindow): void {
this.windows.remove(window); 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. * 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 srf = window.surface;
const visibles = this.windows.getVisibleWindows(srf); const visibles = this.windows.getVisibleWindows(srf);
if (visibles.length < 2) { if (visibles.length < 2) {
@ -455,7 +454,7 @@ export class TilingEngine implements Engine {
* @param window a floating window * @param window a floating window
* @param dir which direction * @param dir which direction
*/ */
public moveFloat(window: Window, dir: Direction): void { public moveFloat(window: EngineWindow, dir: Direction): void {
const srf = window.surface; const srf = window.surface;
// TODO: configurable step size? // TODO: configurable step size?
@ -492,9 +491,9 @@ export class TilingEngine implements Engine {
} }
const state = window.state; const state = window.state;
if (Window.isFloatingState(state)) { if (EngineWindowImpl.isFloatingState(state)) {
this.moveFloat(window, dir); this.moveFloat(window, dir);
} else if (Window.isTiledState(state)) { } else if (EngineWindowImpl.isTiledState(state)) {
this.swapDirection(dir); this.swapDirection(dir);
} }
} }
@ -502,7 +501,7 @@ export class TilingEngine implements Engine {
/** /**
* Toggle float mode of window. * Toggle float mode of window.
*/ */
public toggleFloat(window: Window): void { public toggleFloat(window: EngineWindow): void {
window.state = !window.tileable ? WindowState.Tiled : WindowState.Floating; 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 * Some layouts depend on this assumption, and will make such windows more
* visible than others. * visible than others.
*/ */
public setMaster(window: Window): void { public setMaster(window: EngineWindow): void {
this.windows.setMaster(window); this.windows.setMaster(window);
} }
@ -591,7 +590,7 @@ export class TilingEngine implements Engine {
* Minimize all windows on the surface except the given window. * Minimize all windows on the surface except the given window.
* Used mainly in Monocle mode with config.monocleMinimizeRest * 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)) { for (const tile of this.windows.getVisibleTiles(window.surface)) {
if ( if (
tile.screen == window.screen && 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 vertical: boolean;
let sign: -1 | 1; let sign: -1 | 1;
switch (dir) { switch (dir) {

View File

@ -6,8 +6,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import { Engine } from ".."; import { Engine } from "..";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { import {
Action, Action,
@ -66,7 +65,11 @@ export default class CascadeLayout implements WindowsLayout {
/* nothing */ /* 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); const [vertStep, horzStep] = CascadeLayout.decomposeDirection(this.dir);
// TODO: adjustable step size // TODO: adjustable step size

View File

@ -5,8 +5,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import Rect from "../../util/rect"; import Rect from "../../util/rect";
import { Controller } from "../../controller"; import { Controller } from "../../controller";
@ -20,11 +19,11 @@ export default class FloatingLayout implements WindowsLayout {
public apply( public apply(
_controller: Controller, _controller: Controller,
tileables: Window[], tileables: EngineWindow[],
_area: Rect _area: Rect
): void { ): void {
tileables.forEach( tileables.forEach(
(tileable: Window) => (tileable.state = WindowState.TiledAfloat) (tileable: EngineWindow) => (tileable.state = WindowState.TiledAfloat)
); );
} }

View File

@ -3,7 +3,7 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import Window from "../window"; import { EngineWindow } from "../window";
import { Engine } from ".."; import { Engine } from "..";
import { Controller } from "../../controller"; import { Controller } from "../../controller";
@ -22,8 +22,13 @@ export interface WindowsLayout {
readonly capacity?: number; readonly capacity?: number;
readonly description: string; readonly description: string;
adjust?(area: Rect, tiles: Window[], basis: Window, delta: RectDelta): void; adjust?(
apply(controller: Controller, tileables: Window[], area: Rect): void; area: Rect,
tiles: EngineWindow[],
basis: EngineWindow,
delta: RectDelta
): void;
apply(controller: Controller, tileables: EngineWindow[], area: Rect): void;
executeAction?(engine: Engine, action: Action): void; executeAction?(engine: Engine, action: Action): void;
toString(): string; toString(): string;

View File

@ -5,7 +5,7 @@
import LayoutUtils from "./layout_utils"; import LayoutUtils from "./layout_utils";
import Window from "../window"; import { EngineWindow } from "../window";
import Config from "../../config"; import Config from "../../config";
import Rect from "../../util/rect"; import Rect from "../../util/rect";
@ -14,25 +14,25 @@ import RectDelta from "../../util/rectdelta";
export interface ILayoutPart { export interface ILayoutPart {
adjust( adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): RectDelta; ): RectDelta;
apply(area: Rect, tiles: Window[]): Rect[]; apply(area: Rect, tiles: EngineWindow[]): Rect[];
} }
export class FillLayoutPart implements ILayoutPart { export class FillLayoutPart implements ILayoutPart {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): RectDelta { ): RectDelta {
/* do nothing */ /* do nothing */
return delta; return delta;
} }
public apply(area: Rect, tiles: Window[]): Rect[] { public apply(area: Rect, tiles: EngineWindow[]): Rect[] {
return tiles.map((_tile) => { return tiles.map((_tile) => {
return area; return area;
}); });
@ -74,8 +74,8 @@ export class HalfSplitLayoutPart<L extends ILayoutPart, R extends ILayoutPart>
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): RectDelta { ): RectDelta {
const basisIndex = tiles.indexOf(basis); const basisIndex = tiles.indexOf(basis);
@ -141,7 +141,7 @@ export class HalfSplitLayoutPart<L extends ILayoutPart, R extends ILayoutPart>
} }
} }
public apply(area: Rect, tiles: Window[]): Rect[] { public apply(area: Rect, tiles: EngineWindow[]): Rect[] {
if (tiles.length <= this.primarySize) { if (tiles.length <= this.primarySize) {
/* primary only */ /* primary only */
return this.primary.apply(area, tiles); return this.primary.apply(area, tiles);
@ -183,8 +183,8 @@ export class StackLayoutPart implements ILayoutPart {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): RectDelta { ): RectDelta {
const weights = LayoutUtils.adjustAreaWeights( 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); const weights = tiles.map((tile) => tile.weight);
return LayoutUtils.splitAreaWeighted(area, weights, this.gap); return LayoutUtils.splitAreaWeighted(area, weights, this.gap);
} }
@ -220,8 +220,8 @@ export class RotateLayoutPart<T extends ILayoutPart> implements ILayoutPart {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): RectDelta { ): RectDelta {
// let area = area, delta = delta; // let area = area, delta = delta;
@ -260,7 +260,7 @@ export class RotateLayoutPart<T extends ILayoutPart> implements ILayoutPart {
return delta; return delta;
} }
public apply(area: Rect, tiles: Window[]): Rect[] { public apply(area: Rect, tiles: EngineWindow[]): Rect[] {
switch (this.angle) { switch (this.angle) {
case 0: case 0:
break; break;

View File

@ -5,8 +5,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { import {
Action, Action,
@ -35,7 +34,11 @@ export default class MonocleLayout implements WindowsLayout {
this.config = config; this.config = config;
} }
public apply(controller: Controller, tileables: Window[], area: Rect): void { public apply(
controller: Controller,
tileables: EngineWindow[],
area: Rect
): void {
/* Tile all tileables */ /* Tile all tileables */
tileables.forEach((tile) => { tileables.forEach((tile) => {
tile.state = this.config.monocleMaximize tile.state = this.config.monocleMaximize

View File

@ -5,8 +5,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { clip } from "../../util/func"; import { clip } from "../../util/func";
import Rect from "../../util/rect"; import Rect from "../../util/rect";
@ -41,8 +40,8 @@ export default class QuarterLayout implements WindowsLayout {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): void { ): void {
if (tiles.length <= 1 || tiles.length > 4) { if (tiles.length <= 1 || tiles.length > 4) {
@ -113,7 +112,11 @@ export default class QuarterLayout implements WindowsLayout {
return other; 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++) { for (let i = 0; i < 4 && i < tileables.length; i++) {
tileables[i].state = WindowState.Tiled; tileables[i].state = WindowState.Tiled;
} }

View File

@ -7,8 +7,7 @@ import { HalfSplitLayoutPart } from "./layout_part";
import { FillLayoutPart } from "./layout_part"; import { FillLayoutPart } from "./layout_part";
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import Rect from "../../util/rect"; import Rect from "../../util/rect";
import RectDelta from "../../util/rectdelta"; import RectDelta from "../../util/rectdelta";
@ -42,14 +41,18 @@ export default class SpiralLayout implements WindowsLayout {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): void { ): void {
this.parts.adjust(area, tiles, basis, delta); 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)); tileables.forEach((tileable) => (tileable.state = WindowState.Tiled));
this.bore(tileables.length); this.bore(tileables.length);

View File

@ -5,8 +5,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { import {
Action, Action,
@ -30,7 +29,11 @@ export default class SpreadLayout implements WindowsLayout {
this.space = 0.07; 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 */ /* Tile all tileables */
tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); tileables.forEach((tileable) => (tileable.state = WindowState.Tiled));
const tiles = tileables; const tiles = tileables;

View File

@ -5,8 +5,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { import {
Action, Action,
@ -30,7 +29,11 @@ export default class StairLayout implements WindowsLayout {
this.space = 24; this.space = 24;
} }
public apply(_controller: Controller, tileables: Window[], area: Rect): void { public apply(
_controller: Controller,
tileables: EngineWindow[],
area: Rect
): void {
/* Tile all tileables */ /* Tile all tileables */
tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); tileables.forEach((tileable) => (tileable.state = WindowState.Tiled));
const tiles = tileables; const tiles = tileables;

View File

@ -6,8 +6,7 @@
import { WindowsLayout } from "."; import { WindowsLayout } from ".";
import LayoutUtils from "./layout_utils"; import LayoutUtils from "./layout_utils";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { import {
Action, Action,
@ -48,8 +47,8 @@ export default class ThreeColumnLayout implements WindowsLayout {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): void { ): void {
const basisIndex = tiles.indexOf(basis); const basisIndex = tiles.indexOf(basis);
@ -128,7 +127,10 @@ export default class ThreeColumnLayout implements WindowsLayout {
/* adjust tile weight */ /* adjust tile weight */
const rstackNumTile = Math.floor((tiles.length - this.masterSize) / 2); const rstackNumTile = Math.floor((tiles.length - this.masterSize) / 2);
const [masterTiles, rstackTiles, lstackTiles] = const [masterTiles, rstackTiles, lstackTiles] =
partitionArrayBySizes<Window>(tiles, [this.masterSize, rstackNumTile]); partitionArrayBySizes<EngineWindow>(tiles, [
this.masterSize,
rstackNumTile,
]);
const groupTiles = [lstackTiles, masterTiles, rstackTiles][basisGroup]; const groupTiles = [lstackTiles, masterTiles, rstackTiles][basisGroup];
LayoutUtils.adjustAreaWeights( LayoutUtils.adjustAreaWeights(
area /* we only need height */, 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 */ /* Tile all tileables */
tileables.forEach((tileable) => (tileable.state = WindowState.Tiled)); tileables.forEach((tileable) => (tileable.state = WindowState.Tiled));
const tiles = tileables; const tiles = tileables;
@ -185,7 +191,10 @@ export default class ThreeColumnLayout implements WindowsLayout {
const rstackSize = Math.floor((tiles.length - this.masterSize) / 2); const rstackSize = Math.floor((tiles.length - this.masterSize) / 2);
const [masterTiles, rstackTiles, lstackTiles] = const [masterTiles, rstackTiles, lstackTiles] =
partitionArrayBySizes<Window>(tiles, [this.masterSize, rstackSize]); partitionArrayBySizes<EngineWindow>(tiles, [
this.masterSize,
rstackSize,
]);
[lstackTiles, masterTiles, rstackTiles].forEach((groupTiles, group) => { [lstackTiles, masterTiles, rstackTiles].forEach((groupTiles, group) => {
LayoutUtils.splitAreaWeighted( LayoutUtils.splitAreaWeighted(
groupAreas[group], groupAreas[group],

View File

@ -10,8 +10,7 @@ import {
StackLayoutPart, StackLayoutPart,
} from "./layout_part"; } from "./layout_part";
import Window from "../window"; import { WindowState, EngineWindow } from "../window";
import { WindowState } from "../window";
import { import {
Action, Action,
@ -82,14 +81,18 @@ export default class TileLayout implements WindowsLayout {
public adjust( public adjust(
area: Rect, area: Rect,
tiles: Window[], tiles: EngineWindow[],
basis: Window, basis: EngineWindow,
delta: RectDelta delta: RectDelta
): void { ): void {
this.parts.adjust(area, tiles, basis, delta); 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)); tileables.forEach((tileable) => (tileable.state = WindowState.Tiled));
this.parts.apply(area, tileables).forEach((geometry, i) => { this.parts.apply(area, tileables).forEach((geometry, i) => {

View File

@ -12,14 +12,20 @@ import Rect from "../util/rect";
import RectDelta from "../util/rectdelta"; import RectDelta from "../util/rectdelta";
export enum WindowState { export enum WindowState {
/* initial value */ /**
* Initial value
*/
Unmanaged, Unmanaged,
/* script-external state - overrides internal state */ /**
* Script-external state - overrides internal state
*/
NativeFullscreen, NativeFullscreen,
NativeMaximized, NativeMaximized,
/* script-internal state */ /**
* Script-internal state
*/
Floating, Floating,
Maximized, Maximized,
Tiled, Tiled,
@ -27,7 +33,135 @@ export enum WindowState {
Undecided, 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<Rect>;
/**
* 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 { public static isTileableState(state: WindowState): boolean {
return ( return (
state === WindowState.Tiled || state === WindowState.Tiled ||
@ -69,17 +203,16 @@ export default class Window {
this.window.minimized = min; this.window.minimized = min;
} }
/** If this window ***can be*** tiled by layout. */
public get tileable(): boolean { 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 { 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 { public get floating(): boolean {
return Window.isFloatingState(this.state); return EngineWindowImpl.isFloatingState(this.state);
} }
public get geometryDelta(): RectDelta { public get geometryDelta(): RectDelta {
@ -125,13 +258,13 @@ export default class Window {
if ( if (
(winState === WindowState.Unmanaged || (winState === WindowState.Unmanaged ||
Window.isTileableState(winState)) && EngineWindowImpl.isTileableState(winState)) &&
Window.isFloatingState(value) EngineWindowImpl.isFloatingState(value)
) { ) {
this.shouldCommitFloat = true; this.shouldCommitFloat = true;
} else if ( } else if (
Window.isFloatingState(winState) && EngineWindowImpl.isFloatingState(winState) &&
Window.isTileableState(value) EngineWindowImpl.isTileableState(value)
) { ) {
/* save the current geometry before leaving floating state */ /* save the current geometry before leaving floating state */
this.floatGeometry = this.actualGeometry; this.floatGeometry = this.actualGeometry;
@ -167,6 +300,10 @@ export default class Window {
this.weightMap[srfID] = value; this.weightMap[srfID] = value;
} }
public get isDialog(): boolean {
return this.window.isDialog;
}
private internalState: WindowState; private internalState: WindowState;
private internalStatePreviouslyAskedToChangeTo: WindowState; private internalStatePreviouslyAskedToChangeTo: WindowState;
private shouldCommitFloat: boolean; 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 { public forceSetGeometry(geometry: Rect): void {
this.window.commit(geometry); this.window.commit(geometry);
} }

View File

@ -3,18 +3,22 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import Window from "./window"; import { EngineWindow } from "./window";
import { DriverSurface } from "../driver/surface"; import { DriverSurface } from "../driver/surface";
export default class WindowStore { export default class WindowStore {
public list: Window[]; public list: EngineWindow[];
constructor(windows?: Window[]) { constructor(windows?: EngineWindow[]) {
this.list = windows || []; 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 srcIdx = this.list.indexOf(srcWin);
const destIdx = this.list.indexOf(destWin); const destIdx = this.list.indexOf(destWin);
if (srcIdx === -1 || destIdx === -1) { if (srcIdx === -1 || destIdx === -1) {
@ -25,7 +29,7 @@ export default class WindowStore {
this.list.splice(after ? destIdx + 1 : destIdx, 0, srcWin); 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); const idx = this.list.indexOf(window);
if (idx === -1) { if (idx === -1) {
return; return;
@ -34,7 +38,7 @@ export default class WindowStore {
this.list.splice(0, 0, window); 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 alphaIndex = this.list.indexOf(alpha);
const betaIndex = this.list.indexOf(beta); const betaIndex = this.list.indexOf(beta);
if (alphaIndex < 0 || betaIndex < 0) { if (alphaIndex < 0 || betaIndex < 0) {
@ -51,26 +55,26 @@ export default class WindowStore {
return this.list.length; return this.list.length;
} }
public at(idx: number): Window { public at(idx: number): EngineWindow {
return this.list[idx]; return this.list[idx];
} }
public indexOf(window: Window): number { public indexOf(window: EngineWindow): number {
return this.list.indexOf(window); return this.list.indexOf(window);
} }
public push(window: Window): void { public push(window: EngineWindow): void {
this.list.push(window); this.list.push(window);
} }
public remove(window: Window): void { public remove(window: EngineWindow): void {
const idx = this.list.indexOf(window); const idx = this.list.indexOf(window);
if (idx >= 0) { if (idx >= 0) {
this.list.splice(idx, 1); this.list.splice(idx, 1);
} }
} }
public unshift(window: Window): void { public unshift(window: EngineWindow): void {
this.list.unshift(window); this.list.unshift(window);
} }
//#endregion //#endregion
@ -78,12 +82,12 @@ export default class WindowStore {
//#region Querying Windows //#region Querying Windows
/** Returns all visible windows on the given surface. */ /** 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 this.list.filter((win) => win.visible(srf));
} }
/** Return all visible "Tile" windows on the given surface. */ /** 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)); 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 * Return all visible "tileable" windows on the given surface
* @see Window#tileable * @see Window#tileable
*/ */
public getVisibleTileables(srf: DriverSurface): Window[] { public getVisibleTileables(srf: DriverSurface): EngineWindow[] {
return this.list.filter((win) => win.tileable && win.visible(srf)); return this.list.filter((win) => win.tileable && win.visible(srf));
} }
/** /**
* Return all "tileable" windows on the given surface, including hidden * 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 this.list.filter((win) => win.tileable && win.surface.id === srf.id);
} }
/** Return all windows on this surface, including minimized windows */ /** 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); return this.list.filter((win) => win.surface.id === srf.id);
} }