diff --git a/src/controller/actions/shortcuts.ts b/src/controller/actions/shortcuts.ts index 390ae4a..3d7f9f0 100644 --- a/src/controller/actions/shortcuts.ts +++ b/src/controller/actions/shortcuts.ts @@ -163,6 +163,9 @@ export class ShortcutManager { shortcuts .getCycleEngine() .activated.connect(this.cycleEngine.bind(this)); + shortcuts + .getRestartEngine() + .activated.connect(this.restartEngine.bind(this)); shortcuts .getSwitchBTree() @@ -193,9 +196,11 @@ export class ShortcutManager { return; } if (this.ctrl.windowExtensions.get(window)!.isTiled) { + this.ctrl.windowExtensions.get(window)!.shouldTile = false; this.ctrl.driverManager.untileWindow(window); } else { - this.ctrl.driverManager.addWindow(window); + this.ctrl.windowExtensions.get(window)!.shouldTile = true; + this.ctrl.driverManager.addWindowToPosition(window, null); } this.ctrl.driverManager.rebuildLayout(); } @@ -337,4 +342,27 @@ export class ShortcutManager { this.ctrl.qmlObjects.osd.show(engineName(engineType)); this.ctrl.driverManager.setEngineConfig(desktop, engineConfig); } + + restartEngine(): void { + const desktop = this.ctrl.desktopFactory.createDefaultDesktop(); + const engineConfig = this.ctrl.driverManager.getEngineConfig(desktop); + let engineType = engineConfig.engineType; + if (EngineType.BTree == engineType) { + engineConfig.engineType = EngineType.Half; + } else { + engineConfig.engineType = EngineType.BTree; + } + this.ctrl.driverManager.setEngineConfig(desktop, engineConfig); + engineConfig.engineType = engineType; + this.ctrl.driverManager.setEngineConfig(desktop, engineConfig); + this.ctrl.qmlObjects.osd.show("Restart: " + engineName(engineType)); + this.ctrl.workspace.windows.forEach(window => { + if (this.ctrl.windowExtensions.get(window)!.isTiled) { + this.ctrl.driverManager.untileWindow(window); + this.ctrl.driverManager.rebuildLayout(); + this.ctrl.driverManager.addWindowToPosition(window, null); + this.ctrl.driverManager.rebuildLayout(); + } + }); + } } diff --git a/src/controller/actions/windowhooks.ts b/src/controller/actions/windowhooks.ts index 0cd3a47..138a3f7 100644 --- a/src/controller/actions/windowhooks.ts +++ b/src/controller/actions/windowhooks.ts @@ -2,7 +2,7 @@ import { MaximizeMode, Tile, Window } from "kwin-api"; import { Controller } from "../"; -import { GRect } from "../../util/geometry"; +import { GPoint, GRect } from "../../util/geometry"; import { Log } from "../../util/log"; import { WindowExtensions } from "../extensions"; @@ -24,6 +24,9 @@ export class WindowHooks { window.interactiveMoveResizeStepped.connect( this.interactiveMoveResizeStepped.bind(this), ); + window.interactiveMoveResizeFinished.connect( + this.interactiveMoveResizeFinished.bind(this), + ); window.tileChanged.connect(this.tileChanged.bind(this)); window.fullScreenChanged.connect(this.fullscreenChanged.bind(this)); window.minimizedChanged.connect(this.minimizedChanged.bind(this)); @@ -158,32 +161,25 @@ export class WindowHooks { this.ctrl.driverManager.rebuildLayout(this.window.output); } } + + interactiveMoveResizeFinished() { + if ( + this.ctrl.driverManager.buildingLayout || + this.ctrl.driverManager.resizingLayout || + !this.extensions.shouldTile + ) { + return; + } + this.putWindowInBestTile(false) + } - putWindowInBestTile(): void { - if (this.extensions.lastTiledLocation != null) { - // fancy and illegally long code to place tile in a similar position from when it was untiled - let tile = this.ctrl.workspace - .tilingForScreen(this.window.output) - .bestTileForPosition( - this.extensions.lastTiledLocation.x, - this.extensions.lastTiledLocation.y, - ); - // if its null then its root tile (usually) - if (tile == null) { - tile = this.ctrl.workspace.tilingForScreen( - this.window.output, - ).rootTile; - } - this.ctrl.driverManager.putWindowInTile( - this.window, - tile, - new GRect(tile.absoluteGeometry).directionFromPoint( - this.extensions.lastTiledLocation, - ), - ); - } else { - this.ctrl.driverManager.addWindow(this.window); + putWindowInBestTile(prefer_last: boolean = true): void { + let positionToMatch: GPoint|null = null; // Null uses the middle of the window. + if (this.extensions.lastTiledLocation != null && prefer_last) { + positionToMatch = this.extensions.lastTiledLocation; } + + this.ctrl.driverManager.addWindowToPosition(this.window, positionToMatch); this.ctrl.driverManager.rebuildLayout(this.window.output); } @@ -208,7 +204,7 @@ export class WindowHooks { !this.window.minimized && !(this.extensions.maximized && this.extensions.isSingleMaximized) ) { - this.putWindowInBestTile(); + this.putWindowInBestTile(true); } } diff --git a/src/controller/extensions.ts b/src/controller/extensions.ts index 1075af9..4373ace 100644 --- a/src/controller/extensions.ts +++ b/src/controller/extensions.ts @@ -56,6 +56,7 @@ export class WindowExtensions { private previousDesktopsInternal: Desktop[] = []; isTiled: boolean = false; // not is in a tile, but is registered in engine wasTiled: boolean = false; // windows that were tiled when they could be (minimized/maximized/fullscreen) + shouldTile: boolean = true; lastTiledLocation: GPoint | null = null; clientHooks: WindowHooks | null = null; isSingleMaximized: boolean = false; // whether the window is solo maximized or not (in accordance with maximize single windows) diff --git a/src/driver/index.ts b/src/driver/index.ts index 6e92824..3687a2c 100644 --- a/src/driver/index.ts +++ b/src/driver/index.ts @@ -3,8 +3,8 @@ import { TilingDriver } from "./driver"; import { EngineConfig, TilingEngineFactory } from "../engine"; import { Window, Tile, Output } from "kwin-api"; -import { QTimer } from "kwin-api/qt"; -import { Direction } from "../util/geometry"; +import { QPoint, QTimer } from "kwin-api/qt"; +import { Direction, GRect } from "../util/geometry"; import { Controller } from "../controller"; import { Log } from "../util/log"; import { Config, Borders } from "../util/config"; @@ -262,6 +262,34 @@ export class DriverManager { } } + addWindowToPosition(window: Window, pos: QPoint|null, desktops?: Desktop[]): void { + // If no position is given, use the middle of the window. + if (pos == null) { + pos = { + x: window.pos.x + window.size.width / 2, + y: window.pos.y + window.size.height / 2 + }; + } + + let tile = this.ctrl.workspace + .tilingForScreen(window.output) + .bestTileForPosition(pos.x, pos.y); + + // if its null then its root tile (usually) + if (tile == null) { + tile = this.ctrl.workspace.tilingForScreen( + window.output, + ).rootTile; + } + this.putWindowInTile( + window, + tile, + new GRect(tile.absoluteGeometry).directionFromPoint( + pos, + ), + ); + } + addWindow(window: Window, desktops?: Desktop[]): void { if (desktops == undefined) { desktops = diff --git a/src/extern/qml.ts b/src/extern/qml.ts index 616eb57..1668ed8 100644 --- a/src/extern/qml.ts +++ b/src/extern/qml.ts @@ -57,6 +57,7 @@ export interface Shortcuts { getResizeRight(): ShortcutHandler; getCycleEngine(): ShortcutHandler; + getRestartEngine(): ShortcutHandler; getSwitchBTree(): ShortcutHandler; getSwitchHalf(): ShortcutHandler; getSwitchThreeColumn(): ShortcutHandler; diff --git a/src/qml/shortcuts.qml b/src/qml/shortcuts.qml index 85f97db..0aa0991 100644 --- a/src/qml/shortcuts.qml +++ b/src/qml/shortcuts.qml @@ -160,6 +160,17 @@ Item { sequence: "Meta+Ctrl+L"; } + function getRestartEngine() { + return restartEngine; + } + ShortcutHandler { + id: restartEngine; + + name: "PoloniumRestartEngine"; + text: "Polonium: Restart Engine"; + sequence: "Meta+Shift+R"; + } + function getCycleEngine() { return cycleEngine; }