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 {