diff --git a/res/config.ui b/res/config.ui index 6d69a1f0..7a09aa9c 100644 --- a/res/config.ui +++ b/res/config.ui @@ -381,217 +381,6 @@ - - - - - 50 - false - - - - Directional Keys Behaviors - - - - - - - 50 - false - false - true - - - - Up - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Directional - - - directionalKeyButtonGroup - - - - - - - - 0 - 0 - - - - - 75 - true - - - - DWM style - - - directionalKeyButtonGroup - - - - - - - - 50 - false - false - true - - - - Left - - - Qt::AlignCenter - - - - - - - Focus Next - - - Qt::AlignCenter - - - - - - - - 50 - false - false - true - - - - Down - - - Qt::AlignCenter - - - - - - - - 50 - false - false - true - - - - Right - - - Qt::AlignCenter - - - - - - - Focus Prev - - - Qt::AlignCenter - - - - - - - Adjust Layout - - - Qt::AlignCenter - - - - - - - Adjust Layout - - - Qt::AlignCenter - - - - - - - Focus Up - - - Qt::AlignCenter - - - - - - - Focus Down - - - Qt::AlignCenter - - - - - - - Focus Left - - - Qt::AlignCenter - - - - - - - Focus Right - - - Qt::AlignCenter - - - - - - @@ -873,7 +662,4 @@ - - - diff --git a/res/config.xml b/res/config.xml index 700fb2a7..973a9fc1 100644 --- a/res/config.xml +++ b/res/config.xml @@ -180,16 +180,6 @@ false - - - true - - - - - false - - false diff --git a/src/config.ts b/src/config.ts index a75416c9..6cc7746a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -45,7 +45,6 @@ export default interface Config { //#endregion //#region Behavior - directionalKeyMode: "dwm" | "focus"; newWindowAsMaster: boolean; //#endregion @@ -101,7 +100,6 @@ export class ConfigImpl implements Config { //#endregion //#region Behavior - public directionalKeyMode: "dwm" | "focus"; public newWindowAsMaster: boolean; //#endregion @@ -203,15 +201,6 @@ export class ConfigImpl implements Config { this.screenGapTop = this.kwinApi.KWin.readConfig("screenGapTop", 0); this.tileLayoutGap = this.kwinApi.KWin.readConfig("tileLayoutGap", 0); - const directionalKeyDwm = this.kwinApi.KWin.readConfig( - "directionalKeyDwm", - true - ); - // const directionalKeyFocus = this.kwinApi.KWin.readConfig( - // "directionalKeyFocus", - // false - // ); - this.directionalKeyMode = directionalKeyDwm ? "dwm" : "focus"; this.newWindowAsMaster = this.kwinApi.KWin.readConfig( "newWindowAsMaster", false diff --git a/src/controller/action.ts b/src/controller/action.ts index 1295b01d..a5d804a2 100644 --- a/src/controller/action.ts +++ b/src/controller/action.ts @@ -3,45 +3,434 @@ // // SPDX-License-Identifier: MIT -export enum Action { - Left, - Right, - Up, - Down, +import { Engine } from "../engine"; - /* Alternate HJKL bindings */ - FocusUp, - FocusDown, - FocusLeft, - FocusRight, +/** + * Action that is requested by the user. + */ +export interface Action { + /** + * Action name. It will be displayed it the shortcuts configuration window + */ + readonly name: string; - ShiftLeft, - ShiftRight, - ShiftUp, - ShiftDown, + /** + * The keybinding, that will be assigned to action by default. + */ + readonly defaultKeybinding: string; - SwapUp, - SwapDown, - SwapLeft, - SwapRight, + /** + * Execute action. This is basically a Command Design Pattern. + */ + execute(): void; - GrowWidth, - GrowHeight, - ShrinkWidth, - ShrinkHeight, - - Increase, - Decrease, - ShiftIncrease, - ShiftDecrease, - - ToggleFloat, - ToggleFloatAll, - SetMaster, - NextLayout, - PreviousLayout, - SetLayout, - - Rotate, - RotatePart, + /** + * Execute action, but ignoring any overrides in the process + */ + executeWithoutLayoutOverride(): void; +} + +/** + * Action basic implementation. Provides common grounds for other + * actions. Such as a template of action execution. + */ +abstract class ActionImpl implements Action { + constructor( + protected engine: Engine, + public name: string, + public defaultKeybinding: string + ) {} + + /** + * Action execution pattern. Executes the action override optionally + * defined in the layout and if not found executes the default + * behavior. + */ + public execute(): void { + console.log(`Bismuth: Executing action ${this.name}`); + + const currentLayout = this.engine.currentLayoutOnCurrentSurface(); + if (currentLayout.executeAction) { + currentLayout.executeAction(this.engine, this); + } else { + this.executeWithoutLayoutOverride(); + } + + // TODO: Maybe it worth moving this into engine? + this.engine.arrange(); + } + + /** + * Default action implementation on all layouts + */ + public abstract executeWithoutLayoutOverride(): void; +} + +export class FocusNextWindow extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Focus Next Window", ""); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusOrder(+1); + } +} + +export class FocusPreviousWindow extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Focus Previous Window", ""); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusOrder(-1); + } +} + +export class FocusUpperWindow extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Focus Upper Window", "Meta+K"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusDir("up"); + } +} + +export class FocusBottomWindow extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Focus Bottom Window", "Meta+J"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusDir("down"); + } +} + +export class FocusLeftWindow extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Focus Left Window", "Meta+H"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusDir("left"); + } +} + +export class FocusRightWindow extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Focus Right Window", "Meta+L"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusDir("right"); + } +} + +export class MoveActiveWindowToNextPosition + extends ActionImpl + implements Action +{ + constructor(protected engine: Engine) { + super(engine, "Move Window to the Next Position", ""); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.swapOrder(win, +1); + } + } +} + +export class MoveActiveWindowToPreviousPosition + extends ActionImpl + implements Action +{ + constructor(protected engine: Engine) { + super(engine, "Move Window to the Previous Position", ""); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.swapOrder(win, -1); + } + } +} + +export class MoveActiveWindowUp extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Move Window Up", "Meta+Shift+K"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.swapDirOrMoveFloat("up"); + } +} + +export class MoveActiveWindowDown extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Move Window Down", "Meta+Shift+J"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.swapDirOrMoveFloat("down"); + } +} + +export class MoveActiveWindowLeft extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Move Window Left", "Meta+Shift+H"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.swapDirOrMoveFloat("left"); + } +} + +export class MoveActiveWindowRight extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Move Window Right", "Meta+Shift+L"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.swapDirOrMoveFloat("right"); + } +} + +export class IncreaseActiveWindowWidth extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Increase Window Width", "Meta+Ctrl+L"); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.resizeWindow(win, "east", 1); + } + } +} + +export class IncreaseActiveWindowHeight extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Increase Window Height", "Meta+Ctrl+J"); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.resizeWindow(win, "south", 1); + } + } +} + +export class DecreaseActiveWindowWidth extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Decrease Window Width", "Meta+Ctrl+H"); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.resizeWindow(win, "east", -1); + } + } +} + +export class DecreaseActiveWindowHeight extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Decrease Window Height", "Meta+Ctrl+K"); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.resizeWindow(win, "south", -1); + } + } +} + +export class IncreaseMasterAreaWindowCount + extends ActionImpl + implements Action +{ + constructor(protected engine: Engine) { + super(engine, "Increase Master Area Window Count", "Meta+I"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.showNotification("No Master Area"); + } +} + +export class DecreaseMasterAreaWindowCount + extends ActionImpl + implements Action +{ + constructor(protected engine: Engine) { + super(engine, "Decrease Master Area Window Count", "Meta+D"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.showNotification("No Master Area"); + } +} + +export class IncreaseLayoutMasterAreaSize extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Increase Master Area Size", ""); + } + + public executeWithoutLayoutOverride(): void { + this.engine.showNotification("No Master Area"); + } +} + +export class DecreaseLayoutMasterAreaSize extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Decrease Master Area Size", ""); + } + + public executeWithoutLayoutOverride(): void { + this.engine.showNotification("No Master Area"); + } +} + +export class ToggleActiveWindowFloating extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Toggle Active Window Floating", "Meta+F"); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.toggleFloat(win); + } + } +} + +export class PushActiveWindowIntoMasterAreaFront + extends ActionImpl + implements Action +{ + constructor(protected engine: Engine) { + super(engine, "Push Active Window to Master Area", "Meta+Return"); + } + + public executeWithoutLayoutOverride(): void { + const win = this.engine.currentWindow(); + if (win) { + this.engine.setMaster(win); + } + } +} + +export class SwitchToNextLayout extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Switch to the Next Layout", "Meta+\\"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.cycleLayout(1); + } +} + +export class SwitchToPreviousLayout extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Switch to the Previous Layout", "Meta+|"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.cycleLayout(-1); + } +} + +abstract class SetCurrentLayout extends ActionImpl implements Action { + constructor(protected engine: Engine, protected layoutId: string) { + super(engine, "", ""); + } + + public executeWithoutLayoutOverride(): void { + console.log("Set layout called!"); + + this.engine.setLayout(this.layoutId); + } +} + +export class SetTileLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + super(engine, "TileLayout"); + this.name = "Toggle Tile Layout"; + this.defaultKeybinding = "Meta+T"; + } +} + +export class SetMonocleLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + super(engine, "MonocleLayout"); + this.name = "Toggle Monocle Layout"; + this.defaultKeybinding = "Meta+M"; + } +} + +export class SetThreeColumnLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + super(engine, "ThreeColumnLayout"); + this.name = "Toggle Three Column Layout"; + this.defaultKeybinding = ""; + } +} + +export class SetSpreadLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + super(engine, "SpreadLayout"); + this.name = "Toggle Spread Layout"; + this.defaultKeybinding = ""; + } +} + +export class SetStairLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + super(engine, "StairLayout"); + this.name = "Toggle Stair Layout"; + this.defaultKeybinding = ""; + } +} + +export class SetFloatingLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + // NOTE: space is intentional (Temporary) + super(engine, "FloatingLayout "); + this.name = "Toggle Stair Layout"; + this.defaultKeybinding = "Meta+Shift+F"; + } +} + +export class SetQuarterLayout extends SetCurrentLayout { + constructor(protected engine: Engine) { + // NOTE: space is intentional (Temporary) + super(engine, "QuarterLayout "); + this.name = "Toggle Quarter Layout"; + this.defaultKeybinding = ""; + } +} + +export class Rotate extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Rotate", "Meta+R"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusDir("left"); + } +} + +export class RotatePart extends ActionImpl implements Action { + constructor(protected engine: Engine) { + super(engine, "Rotate Part", "Meta+Shift+R"); + } + + public executeWithoutLayoutOverride(): void { + this.engine.focusDir("left"); + } } diff --git a/src/controller/index.ts b/src/controller/index.ts index 533141ff..e512dbc2 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -3,8 +3,6 @@ // // SPDX-License-Identifier: MIT -import { Action } from "./action"; - import { Engine, TilingEngine } from "../engine"; import Window from "../engine/window"; import { WindowState } from "../engine/window"; @@ -15,6 +13,8 @@ import { DriverSurface } from "../driver/surface"; import Config from "../config"; import Debug from "../util/debug"; +import * as Action from "./action"; + /** * Entry point of the script (apart from QML). Handles the user input (shortcuts) * and the events from the Driver (in other words KWin, the window manager/compositor). @@ -139,13 +139,6 @@ export interface Controller { */ onWindowFocused(window: Window): void; - /** - * React to a particular keyboard shortcut action from the user. - * @param input the shortcut action. For example focus the next window, or change the layout. - * @param data the action optional data, that it could held. For example the layout name to which user want to change. - */ - onShortcut(input: Action, data?: any): void; - /** * Ask engine to manage the window * @param win the window which needs to be managed. @@ -176,7 +169,7 @@ export class TilingController implements Controller { this.debug.debug(() => `Config: ${this.config}`); this.driver.bindEvents(); - this.driver.bindShortcuts(); + this.bindShortcuts(); this.driver.manageWindows(); @@ -348,140 +341,55 @@ export class TilingController implements Controller { window.timestamp = new Date().getTime(); } - public onShortcut(input: Action, data?: string): void { - if (this.config.directionalKeyMode === "focus") { - switch (input) { - case Action.Up: - input = Action.FocusUp; - break; - case Action.Down: - input = Action.FocusDown; - break; - case Action.Left: - input = Action.FocusLeft; - break; - case Action.Right: - input = Action.FocusRight; - break; - - case Action.ShiftUp: - input = Action.SwapUp; - break; - case Action.ShiftDown: - input = Action.SwapDown; - break; - case Action.ShiftLeft: - input = Action.SwapLeft; - break; - case Action.ShiftRight: - input = Action.SwapRight; - break; - } - } - - if (this.engine.handleLayoutShortcut(input, data)) { - this.engine.arrange(); - return; - } - - const window = this.currentWindow; - switch (input) { - case Action.Up: - this.engine.focusOrder(-1); - break; - case Action.Down: - this.engine.focusOrder(+1); - break; - - case Action.FocusUp: - this.engine.focusDir("up"); - break; - case Action.FocusDown: - this.engine.focusDir("down"); - break; - case Action.FocusLeft: - this.engine.focusDir("left"); - break; - case Action.FocusRight: - this.engine.focusDir("right"); - break; - - case Action.GrowWidth: - if (window) { - this.engine.resizeWindow(window, "east", 1); - } - break; - case Action.ShrinkWidth: - if (window) { - this.engine.resizeWindow(window, "east", -1); - } - break; - case Action.GrowHeight: - if (window) { - this.engine.resizeWindow(window, "south", 1); - } - break; - case Action.ShrinkHeight: - if (window) { - this.engine.resizeWindow(window, "south", -1); - } - break; - - case Action.ShiftUp: - if (window) { - this.engine.swapOrder(window, -1); - } - break; - case Action.ShiftDown: - if (window) { - this.engine.swapOrder(window, +1); - } - break; - - case Action.SwapUp: - this.engine.swapDirOrMoveFloat("up"); - break; - case Action.SwapDown: - this.engine.swapDirOrMoveFloat("down"); - break; - case Action.SwapLeft: - this.engine.swapDirOrMoveFloat("left"); - break; - case Action.SwapRight: - this.engine.swapDirOrMoveFloat("right"); - break; - - case Action.SetMaster: - if (window) { - this.engine.setMaster(window); - } - break; - case Action.ToggleFloat: - if (window) { - this.engine.toggleFloat(window); - } - break; - case Action.ToggleFloatAll: - this.engine.floatAll(this.currentSurface); - break; - - case Action.NextLayout: - this.engine.cycleLayout(1); - break; - case Action.PreviousLayout: - this.engine.cycleLayout(-1); - break; - case Action.SetLayout: - if (typeof data === "string") { - this.engine.setLayout(data); - } - break; - } - - this.engine.arrange(); - } - public manageWindow(win: Window): void { this.engine.manage(win); } + + private bindShortcuts(): void { + const allPossibleActions = [ + new Action.FocusNextWindow(this.engine), + new Action.FocusPreviousWindow(this.engine), + new Action.FocusUpperWindow(this.engine), + new Action.FocusBottomWindow(this.engine), + new Action.FocusLeftWindow(this.engine), + new Action.FocusRightWindow(this.engine), + new Action.MoveActiveWindowToNextPosition(this.engine), + + new Action.MoveActiveWindowToPreviousPosition(this.engine), + new Action.MoveActiveWindowUp(this.engine), + new Action.MoveActiveWindowDown(this.engine), + new Action.MoveActiveWindowLeft(this.engine), + new Action.MoveActiveWindowRight(this.engine), + + new Action.IncreaseActiveWindowWidth(this.engine), + new Action.IncreaseActiveWindowHeight(this.engine), + new Action.DecreaseActiveWindowWidth(this.engine), + new Action.DecreaseActiveWindowHeight(this.engine), + + new Action.IncreaseMasterAreaWindowCount(this.engine), + new Action.DecreaseMasterAreaWindowCount(this.engine), + new Action.IncreaseLayoutMasterAreaSize(this.engine), + new Action.DecreaseLayoutMasterAreaSize(this.engine), + + new Action.ToggleActiveWindowFloating(this.engine), + new Action.PushActiveWindowIntoMasterAreaFront(this.engine), + + new Action.SwitchToNextLayout(this.engine), + new Action.SwitchToPreviousLayout(this.engine), + new Action.SetTileLayout(this.engine), + new Action.SetMonocleLayout(this.engine), + new Action.SetThreeColumnLayout(this.engine), + new Action.SetStairLayout(this.engine), + new Action.SetSpreadLayout(this.engine), + new Action.SetFloatingLayout(this.engine), + new Action.SetQuarterLayout(this.engine), + + new Action.Rotate(this.engine), + new Action.RotatePart(this.engine), + ]; + + for (const action of allPossibleActions) { + this.driver.bindShortcut(action); + } + } } diff --git a/src/driver/index.ts b/src/driver/index.ts index 94be0384..3fd06ecc 100644 --- a/src/driver/index.ts +++ b/src/driver/index.ts @@ -13,17 +13,8 @@ import { Action } from "../controller/action"; import Window from "../engine/window"; -import { WindowsLayoutClass } from "../engine/layout"; import { WindowState } from "../engine/window"; -import MonocleLayout from "../engine/layout/monocle_layout"; -import TileLayout from "../engine/layout/tile_layout"; -import ThreeColumnLayout from "../engine/layout/three_column_layout"; -import StairLayout from "../engine/layout/stair_layout"; -import SpreadLayout from "../engine/layout/spread_layout"; -import FloatingLayout from "../engine/layout/floating_layout"; -import QuarterLayout from "../engine/layout/quarter_layout"; - import Config from "../config"; import Debug from "../util/debug"; import qmlSetTimeout, { TimersPool } from "../util/timer"; @@ -38,7 +29,7 @@ export interface DriverContext { showNotification(text: string): void; bindEvents(): void; - bindShortcuts(): void; + bindShortcut(action: Action): void; manageWindows(): void; } @@ -302,14 +293,6 @@ export class KWinDriver implements DriverContext { * https://github.com/KDE/kwin/blob/master/scripts/minimizeall/contents/code/main.js */ } - /** - * Register Bismuth shortcuts - */ - public bindShortcuts(): void { - this.bindMainShortcuts(); - this.bindLayoutShortcuts(); - } - /** * Manage the windows */ @@ -343,67 +326,18 @@ export class KWinDriver implements DriverContext { this.qml.popupDialog.show(text); } - private bindMainShortcuts(): void { - const bind = (seq: string, title: string, action: Action): void => { - title = "Bismuth: " + title; - seq = "Meta+" + seq; - this.kwinApi.KWin.registerShortcut(title, "", seq, () => { - this.enter(() => this.controller.onShortcut(action)); - }); - }; + public bindShortcut(action: Action): void { + const shortcutUITitle = `Bismuth: ${action.name}`; - bind("J", "Down/Next", Action.Down); - bind("K", "Up/Prev", Action.Up); - bind("H", "Left", Action.Left); - bind("L", "Right", Action.Right); - - bind("Shift+J", "Move Down/Next", Action.ShiftDown); - bind("Shift+K", "Move Up/Prev", Action.ShiftUp); - bind("Shift+H", "Move Left", Action.ShiftLeft); - bind("Shift+L", "Move Right", Action.ShiftRight); - - bind("Ctrl+J", "Grow Height", Action.GrowHeight); - bind("Ctrl+K", "Shrink Height", Action.ShrinkHeight); - bind("Ctrl+H", "Shrink Width", Action.ShrinkWidth); - bind("Ctrl+L", "Grow Width", Action.GrowWidth); - - bind("I", "Increase", Action.Increase); - bind("D", "Decrease", Action.Decrease); - - bind("F", "Float", Action.ToggleFloat); - bind("Shift+F", "Float All", Action.ToggleFloatAll); - bind("", "Cycle Layout", Action.NextLayout); // TODO: remove this shortcut - bind("\\", "Next Layout", Action.NextLayout); - bind("|", "Previous Layout", Action.PreviousLayout); - - bind("R", "Rotate", Action.Rotate); - bind("Shift+R", "Rotate Part", Action.RotatePart); - - bind("Return", "Set master", Action.SetMaster); - } - - private bindLayoutShortcuts(): void { - const bind = ( - seq: string, - title: string, - layoutClass: WindowsLayoutClass - ): void => { - title = "Bismuth: " + title + " Layout"; - seq = seq !== "" ? "Meta+" + seq : ""; - this.kwinApi.KWin.registerShortcut(title, "", seq, () => { - this.enter(() => - this.controller.onShortcut(Action.SetLayout, layoutClass.id) - ); - }); - }; - - bind("T", "Tile", TileLayout); - bind("M", "Monocle", MonocleLayout); - bind("", "Three Column", ThreeColumnLayout); - bind("", "Spread", SpreadLayout); - bind("", "Stair", StairLayout); - bind("", "Floating", FloatingLayout); - bind("", "Quarter", QuarterLayout); + console.log(`Registering ${shortcutUITitle}`); + this.kwinApi.KWin.registerShortcut( + shortcutUITitle, + "", + action.defaultKeybinding, + (): void => { + this.enter(() => action.execute()); + } + ); } /** diff --git a/src/engine/index.ts b/src/engine/index.ts index 294a8fc3..55f95b27 100644 --- a/src/engine/index.ts +++ b/src/engine/index.ts @@ -49,7 +49,8 @@ export interface Engine { step: -1 | 1 ): void; enforceSize(window: Window): void; - handleLayoutShortcut(input: Action, data?: any): boolean; + currentLayoutOnCurrentSurface(): WindowsLayout; + currentWindow(): Window | null; focusOrder(step: -1 | 1): void; focusDir(dir: Direction): void; swapOrder(window: Window, step: -1 | 1): void; @@ -301,6 +302,14 @@ export class TilingEngine implements Engine { this.debug.debugObj(() => ["arrangeScreen/finished", { screenSurface }]); } + public currentLayoutOnCurrentSurface(): WindowsLayout { + return this.layouts.getCurrentLayout(this.controller.currentSurface); + } + + public currentWindow(): Window | null { + return this.controller.currentWindow; + } + /** * Re-apply window geometry, computed by layout algorithm. * @@ -561,21 +570,6 @@ export class TilingEngine implements Engine { } } - /** - * Let the current layout override shortcut. - * - * @returns True if the layout overrides the shortcut. False, otherwise. - */ - public handleLayoutShortcut(input: Action, data?: string): boolean { - const layout = this.layouts.getCurrentLayout( - this.controller.currentSurface - ); - if (layout.handleShortcut) { - return layout.handleShortcut(this, input, data); - } - return false; - } - private getNeighborByDirection(basis: Window, dir: Direction): Window | null { let vertical: boolean; let sign: -1 | 1; diff --git a/src/engine/layout/cascade_layout.ts b/src/engine/layout/cascade_layout.ts index e960083d..46dc1cfa 100644 --- a/src/engine/layout/cascade_layout.ts +++ b/src/engine/layout/cascade_layout.ts @@ -9,7 +9,11 @@ import { Engine } from ".."; import Window from "../window"; import { WindowState } from "../window"; -import { Action } from "../../controller/action"; +import { + Action, + DecreaseMasterAreaWindowCount, + IncreaseMasterAreaWindowCount, +} from "../../controller/action"; import { Controller } from "../../controller"; import Rect from "../../util/rect"; @@ -95,23 +99,15 @@ export default class CascadeLayout implements WindowsLayout { return new CascadeLayout(this.dir); } - public handleShortcut( - engine: Engine, - input: Action, - _data?: string - ): boolean { - switch (input) { - case Action.Increase: - this.dir = (this.dir + 1 + 8) % 8; - engine.showNotification(this.description); - break; - case Action.Decrease: - this.dir = (this.dir - 1 + 8) % 8; - engine.showNotification(this.description); - break; - default: - return false; + public executeAction(engine: Engine, action: Action): void { + if (action instanceof IncreaseMasterAreaWindowCount) { + this.dir = (this.dir + 1 + 8) % 8; + engine.showNotification(this.description); + } else if (action instanceof DecreaseMasterAreaWindowCount) { + this.dir = (this.dir - 1 + 8) % 8; + engine.showNotification(this.description); + } else { + action.executeWithoutLayoutOverride(); } - return true; } } diff --git a/src/engine/layout/index.ts b/src/engine/layout/index.ts index cfeb8bdf..84577813 100644 --- a/src/engine/layout/index.ts +++ b/src/engine/layout/index.ts @@ -24,7 +24,7 @@ export interface WindowsLayout { adjust?(area: Rect, tiles: Window[], basis: Window, delta: RectDelta): void; apply(controller: Controller, tileables: Window[], area: Rect): void; - handleShortcut?(engine: Engine, input: Action, data?: any): boolean; + executeAction?(engine: Engine, action: Action): void; toString(): string; } diff --git a/src/engine/layout/monocle_layout.ts b/src/engine/layout/monocle_layout.ts index a6d017e7..9805f114 100644 --- a/src/engine/layout/monocle_layout.ts +++ b/src/engine/layout/monocle_layout.ts @@ -10,7 +10,15 @@ import { WindowState } from "../window"; import { KWinWindow } from "../../driver/window"; -import { Action } from "../../controller/action"; +import { + Action, + FocusBottomWindow, + FocusLeftWindow, + FocusNextWindow, + FocusPreviousWindow, + FocusRightWindow, + FocusUpperWindow, +} from "../../controller/action"; import Rect from "../../util/rect"; import Config from "../../config"; @@ -60,26 +68,22 @@ export default class MonocleLayout implements WindowsLayout { return this; } - public handleShortcut( - engine: Engine, - input: Action, - _data?: string - ): boolean { - switch (input) { - case Action.Up: - case Action.FocusUp: - case Action.Left: - case Action.FocusLeft: - engine.focusOrder(-1); - return true; - case Action.Down: - case Action.FocusDown: - case Action.Right: - case Action.FocusRight: - engine.focusOrder(1); - return true; - default: - return false; + public executeAction(engine: Engine, action: Action): void { + if ( + action instanceof FocusUpperWindow || + action instanceof FocusLeftWindow || + action instanceof FocusPreviousWindow + ) { + engine.focusOrder(-1); + } else if ( + action instanceof FocusBottomWindow || + action instanceof FocusRightWindow || + action instanceof FocusNextWindow + ) { + engine.focusOrder(1); + } else { + console.log("Executing from Monocle regular action!"); + action.executeWithoutLayoutOverride(); } } diff --git a/src/engine/layout/spread_layout.ts b/src/engine/layout/spread_layout.ts index daba1cf3..c6c4fe80 100644 --- a/src/engine/layout/spread_layout.ts +++ b/src/engine/layout/spread_layout.ts @@ -8,7 +8,11 @@ import { WindowsLayout } from "."; import Window from "../window"; import { WindowState } from "../window"; -import { Action } from "../../controller/action"; +import { + Action, + DecreaseMasterAreaWindowCount, + IncreaseMasterAreaWindowCount, +} from "../../controller/action"; import Rect from "../../util/rect"; import { Controller } from "../../controller"; @@ -58,20 +62,16 @@ export default class SpreadLayout implements WindowsLayout { return other; } - public handleShortcut(_engine: Engine, input: Action): boolean { - switch (input) { - case Action.Decrease: - // TODO: define arbitrary constants - this.space = Math.max(0.04, this.space - 0.01); - break; - case Action.Increase: - // TODO: define arbitrary constants - this.space = Math.min(0.1, this.space + 0.01); - break; - default: - return false; + public executeAction(_engine: Engine, action: Action): void { + if (action instanceof DecreaseMasterAreaWindowCount) { + // TODO: define arbitrary constants + this.space = Math.max(0.04, this.space - 0.01); + } else if (action instanceof IncreaseMasterAreaWindowCount) { + // TODO: define arbitrary constants + this.space = Math.min(0.1, this.space + 0.01); + } else { + action.executeWithoutLayoutOverride(); } - return true; } public toString(): string { diff --git a/src/engine/layout/stair_layout.ts b/src/engine/layout/stair_layout.ts index 04084c14..2fb164ad 100644 --- a/src/engine/layout/stair_layout.ts +++ b/src/engine/layout/stair_layout.ts @@ -8,7 +8,11 @@ import { WindowsLayout } from "."; import Window from "../window"; import { WindowState } from "../window"; -import { Action } from "../../controller/action"; +import { + Action, + DecreaseMasterAreaWindowCount, + IncreaseMasterAreaWindowCount, +} from "../../controller/action"; import Rect from "../../util/rect"; import { Controller } from "../../controller"; @@ -54,20 +58,16 @@ export default class StairLayout implements WindowsLayout { return other; } - public handleShortcut(_engine: Engine, input: Action): boolean { - switch (input) { - case Action.Decrease: - // TODO: define arbitrary constants - this.space = Math.max(16, this.space - 8); - break; - case Action.Increase: - // TODO: define arbitrary constants - this.space = Math.min(160, this.space + 8); - break; - default: - return false; + public executeAction(_engine: Engine, action: Action): void { + if (action instanceof DecreaseMasterAreaWindowCount) { + // TODO: define arbitrary constants + this.space = Math.max(16, this.space - 8); + } else if (action instanceof IncreaseMasterAreaWindowCount) { + // TODO: define arbitrary constants + this.space = Math.min(160, this.space + 8); + } else { + action.executeWithoutLayoutOverride(); } - return true; } public toString(): string { diff --git a/src/engine/layout/three_column_layout.ts b/src/engine/layout/three_column_layout.ts index df43178b..28958672 100644 --- a/src/engine/layout/three_column_layout.ts +++ b/src/engine/layout/three_column_layout.ts @@ -9,7 +9,13 @@ import LayoutUtils from "./layout_utils"; import Window from "../window"; import { WindowState } from "../window"; -import { Action } from "../../controller/action"; +import { + Action, + DecreaseLayoutMasterAreaSize, + DecreaseMasterAreaWindowCount, + IncreaseLayoutMasterAreaSize, + IncreaseMasterAreaWindowCount, +} from "../../controller/action"; import { partitionArrayBySizes, clip, slide } from "../../util/func"; import Rect from "../../util/rect"; @@ -197,34 +203,25 @@ export default class ThreeColumnLayout implements WindowsLayout { return other; } - public handleShortcut( - engine: Engine, - input: Action, - _data?: string - ): boolean { - switch (input) { - case Action.Increase: - this.resizeMaster(engine, +1); - return true; - case Action.Decrease: - this.resizeMaster(engine, -1); - return true; - case Action.Left: - this.masterRatio = clip( - slide(this.masterRatio, -0.05), - ThreeColumnLayout.MIN_MASTER_RATIO, - ThreeColumnLayout.MAX_MASTER_RATIO - ); - return true; - case Action.Right: - this.masterRatio = clip( - slide(this.masterRatio, +0.05), - ThreeColumnLayout.MIN_MASTER_RATIO, - ThreeColumnLayout.MAX_MASTER_RATIO - ); - return true; - default: - return false; + public executeAction(engine: Engine, action: Action): void { + if (action instanceof IncreaseMasterAreaWindowCount) { + this.resizeMaster(engine, +1); + } else if (action instanceof DecreaseMasterAreaWindowCount) { + this.resizeMaster(engine, -1); + } else if (action instanceof DecreaseLayoutMasterAreaSize) { + this.masterRatio = clip( + slide(this.masterRatio, -0.05), + ThreeColumnLayout.MIN_MASTER_RATIO, + ThreeColumnLayout.MAX_MASTER_RATIO + ); + } else if (action instanceof IncreaseLayoutMasterAreaSize) { + this.masterRatio = clip( + slide(this.masterRatio, +0.05), + ThreeColumnLayout.MIN_MASTER_RATIO, + ThreeColumnLayout.MAX_MASTER_RATIO + ); + } else { + action.executeWithoutLayoutOverride(); } } diff --git a/src/engine/layout/tile_layout.ts b/src/engine/layout/tile_layout.ts index 843660cd..bb4ddb24 100644 --- a/src/engine/layout/tile_layout.ts +++ b/src/engine/layout/tile_layout.ts @@ -13,7 +13,15 @@ import { import Window from "../window"; import { WindowState } from "../window"; -import { Action } from "../../controller/action"; +import { + Action, + DecreaseLayoutMasterAreaSize, + DecreaseMasterAreaWindowCount, + IncreaseLayoutMasterAreaSize, + IncreaseMasterAreaWindowCount, + Rotate, + RotatePart, +} from "../../controller/action"; import { clip, slide } from "../../util/func"; import Rect from "../../util/rect"; @@ -96,45 +104,37 @@ export default class TileLayout implements WindowsLayout { return other; } - public handleShortcut(engine: Engine, input: Action): boolean { - switch (input) { - case Action.Left: - this.masterRatio = clip( - slide(this.masterRatio, -0.05), - TileLayout.MIN_MASTER_RATIO, - TileLayout.MAX_MASTER_RATIO - ); - break; - case Action.Right: - this.masterRatio = clip( - slide(this.masterRatio, +0.05), - TileLayout.MIN_MASTER_RATIO, - TileLayout.MAX_MASTER_RATIO - ); - break; - case Action.Increase: - // TODO: define arbitrary constant - if (this.numMaster < 10) { - this.numMaster += 1; - } - engine.showNotification(this.description); - break; - case Action.Decrease: - if (this.numMaster > 0) { - this.numMaster -= 1; - } - engine.showNotification(this.description); - break; - case Action.Rotate: - this.parts.rotate(90); - break; - case Action.RotatePart: - this.parts.inner.primary.rotate(90); - break; - default: - return false; + public executeAction(engine: Engine, action: Action): void { + if (action instanceof DecreaseLayoutMasterAreaSize) { + this.masterRatio = clip( + slide(this.masterRatio, -0.05), + TileLayout.MIN_MASTER_RATIO, + TileLayout.MAX_MASTER_RATIO + ); + } else if (action instanceof IncreaseLayoutMasterAreaSize) { + this.masterRatio = clip( + slide(this.masterRatio, +0.05), + TileLayout.MIN_MASTER_RATIO, + TileLayout.MAX_MASTER_RATIO + ); + } else if (action instanceof IncreaseMasterAreaWindowCount) { + // TODO: define arbitrary constant + if (this.numMaster < 10) { + this.numMaster += 1; + } + engine.showNotification(this.description); + } else if (action instanceof DecreaseMasterAreaWindowCount) { + if (this.numMaster > 0) { + this.numMaster -= 1; + } + engine.showNotification(this.description); + } else if (action instanceof Rotate) { + this.parts.rotate(90); + } else if (action instanceof RotatePart) { + this.parts.inner.primary.rotate(90); + } else { + action.executeWithoutLayoutOverride(); } - return true; } public toString(): string {