fix: 🔥 Pass config object instead of global

QML JS engine does not allow global objects
This commit is contained in:
Mikhail Zolotukhin 2021-09-02 14:57:00 +03:00
parent 3b87e93883
commit 33ae26a35b
20 changed files with 406 additions and 354 deletions

27
src/config.d.ts vendored
View File

@ -1,27 +0,0 @@
// Copyright (c) 2018-2019 Eon S. Jeon <esjeon@hyunmu.am>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import IConfig from "./iconfig";
import KWinConfig from "./driver/kwin/kwin_config";
declare global {
var CONFIG: IConfig;
var KWINCONFIG: KWinConfig;
}

223
src/config.ts Normal file
View File

@ -0,0 +1,223 @@
// Copyright (c) 2018-2019 Eon S. Jeon <esjeon@hyunmu.am>
// Copyright (c) 2021 Mikhail Zolotukhin <mail@genda.life>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import MonocleLayout from "./layouts/monocle_layout";
import TileLayout from "./layouts/tile_layout";
import ThreeColumnLayout from "./layouts/three_column_layout";
import StairLayout from "./layouts/stair_layout";
import SpiralLayout from "./layouts/spiral_layout";
import SpreadLayout from "./layouts/spread_layout";
import FloatingLayout from "./layouts/floating_layout";
import QuarterLayout from "./layouts/quarter_layout";
import CascadeLayout from "./layouts/cascade_layout";
import { ILayout } from "./ilayout";
import { ILayoutClass } from "./ilayout";
import { debug } from "./util/debug";
export default interface IConfig {
//#region Layout
layoutOrder: string[];
layoutFactories: { [key: string]: () => ILayout };
monocleMaximize: boolean;
maximizeSoleTile: boolean;
monocleMinimizeRest: boolean; // KWin-specific
//#endregion
//#region Features
adjustLayout: boolean;
adjustLayoutLive: boolean;
keepFloatAbove: boolean;
noTileBorder: boolean;
limitTileWidthRatio: number;
//#endregion
//#region Gap
screenGapBottom: number;
screenGapLeft: number;
screenGapRight: number;
screenGapTop: number;
tileLayoutGap: number;
//#endregion
//#region Behavior
directionalKeyMode: "dwm" | "focus";
newWindowAsMaster: boolean;
//#endregion
//#region KWin-specific
layoutPerActivity: boolean;
layoutPerDesktop: boolean;
preventMinimize: boolean;
preventProtrusion: boolean;
pollMouseXdotool: boolean;
//#endregion
//#region KWin-specific Rules
floatUtility: boolean;
floatingClass: string[];
floatingTitle: string[];
ignoreClass: string[];
ignoreTitle: string[];
ignoreRole: string[];
ignoreActivity: string[];
ignoreScreen: number[];
//#endregion
}
export class Config implements IConfig {
//#region Layout
public layoutOrder: string[];
public layoutFactories: { [key: string]: () => ILayout };
public maximizeSoleTile: boolean;
public monocleMaximize: boolean;
public monocleMinimizeRest: boolean; // KWin-specific
//#endregion
//#region Features
public adjustLayout: boolean;
public adjustLayoutLive: boolean;
public keepFloatAbove: boolean;
public noTileBorder: boolean;
public limitTileWidthRatio: number;
//#endregion
//#region Gap
public screenGapBottom: number;
public screenGapLeft: number;
public screenGapRight: number;
public screenGapTop: number;
public tileLayoutGap: number;
//#endregion
//#region Behavior
public directionalKeyMode: "dwm" | "focus";
public newWindowAsMaster: boolean;
//#endregion
//#region KWin-specific
public layoutPerActivity: boolean;
public layoutPerDesktop: boolean;
public preventMinimize: boolean;
public preventProtrusion: boolean;
public pollMouseXdotool: boolean;
//#endregion
//#region KWin-specific Rules
public floatUtility: boolean;
public floatingClass: string[];
public floatingTitle: string[];
public ignoreClass: string[];
public ignoreTitle: string[];
public ignoreRole: string[];
public ignoreActivity: string[];
public ignoreScreen: number[];
//#endregion
constructor() {
function commaSeparate(str: string): string[] {
if (!str || typeof str !== "string") return [];
return str.split(",").map((part) => part.trim());
}
DEBUG.enabled = DEBUG.enabled || KWin.readConfig("debug", false);
this.layoutOrder = [];
this.layoutFactories = {};
(
[
["enableTileLayout", true, TileLayout],
["enableMonocleLayout", true, MonocleLayout],
["enableThreeColumnLayout", true, ThreeColumnLayout],
["enableSpreadLayout", true, SpreadLayout],
["enableStairLayout", true, StairLayout],
["enableSpiralLayout", true, SpiralLayout],
["enableQuarterLayout", false, QuarterLayout],
["enableFloatingLayout", false, FloatingLayout],
["enableCascadeLayout", false, CascadeLayout], // TODO: add config
] as Array<[string, boolean, ILayoutClass]>
).forEach(([configKey, defaultValue, layoutClass]) => {
if (KWin.readConfig(configKey, defaultValue))
this.layoutOrder.push(layoutClass.id);
// TODO: Refactor this: config should not create factories. It is not its responsibility
this.layoutFactories[layoutClass.id] = () => new layoutClass(this);
});
this.maximizeSoleTile = KWin.readConfig("maximizeSoleTile", false);
this.monocleMaximize = KWin.readConfig("monocleMaximize", true);
this.monocleMinimizeRest = KWin.readConfig("monocleMinimizeRest", false);
this.adjustLayout = KWin.readConfig("adjustLayout", true);
this.adjustLayoutLive = KWin.readConfig("adjustLayoutLive", true);
this.keepFloatAbove = KWin.readConfig("keepFloatAbove", true);
this.noTileBorder = KWin.readConfig("noTileBorder", false);
this.limitTileWidthRatio = 0;
if (KWin.readConfig("limitTileWidth", false))
this.limitTileWidthRatio = KWin.readConfig("limitTileWidthRatio", 1.6);
this.screenGapBottom = KWin.readConfig("screenGapBottom", 0);
this.screenGapLeft = KWin.readConfig("screenGapLeft", 0);
this.screenGapRight = KWin.readConfig("screenGapRight", 0);
this.screenGapTop = KWin.readConfig("screenGapTop", 0);
this.tileLayoutGap = KWin.readConfig("tileLayoutGap", 0);
const directionalKeyDwm = KWin.readConfig("directionalKeyDwm", true);
const directionalKeyFocus = KWin.readConfig("directionalKeyFocus", false);
this.directionalKeyMode = directionalKeyDwm ? "dwm" : "focus";
this.newWindowAsMaster = KWin.readConfig("newWindowAsMaster", false);
this.layoutPerActivity = KWin.readConfig("layoutPerActivity", true);
this.layoutPerDesktop = KWin.readConfig("layoutPerDesktop", true);
this.floatUtility = KWin.readConfig("floatUtility", true);
this.preventMinimize = KWin.readConfig("preventMinimize", false);
this.preventProtrusion = KWin.readConfig("preventProtrusion", true);
this.pollMouseXdotool = KWin.readConfig("pollMouseXdotool", false);
this.floatingClass = commaSeparate(KWin.readConfig("floatingClass", ""));
this.floatingTitle = commaSeparate(KWin.readConfig("floatingTitle", ""));
this.ignoreActivity = commaSeparate(KWin.readConfig("ignoreActivity", ""));
this.ignoreClass = commaSeparate(
KWin.readConfig("ignoreClass", "krunner,yakuake,spectacle,kded5")
);
this.ignoreRole = commaSeparate(KWin.readConfig("ignoreRole", "quake"));
this.ignoreScreen = commaSeparate(KWin.readConfig("ignoreScreen", "")).map(
(str) => parseInt(str, 10)
);
this.ignoreTitle = commaSeparate(KWin.readConfig("ignoreTitle", ""));
if (this.preventMinimize && this.monocleMinimizeRest) {
debug(
() => "preventMinimize is disabled because of monocleMinimizeRest."
);
this.preventMinimize = false;
}
}
public toString(): string {
return "Config(" + JSON.stringify(this, undefined, 2) + ")";
}
}

View File

@ -17,154 +17,3 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import MonocleLayout from "../../layouts/monocle_layout";
import TileLayout from "../../layouts/tile_layout";
import ThreeColumnLayout from "../../layouts/three_column_layout";
import StairLayout from "../../layouts/stair_layout";
import SpiralLayout from "../../layouts/spiral_layout";
import SpreadLayout from "../../layouts/spread_layout";
import FloatingLayout from "../../layouts/floating_layout";
import QuarterLayout from "../../layouts/quarter_layout";
import CascadeLayout from "../../layouts/cascade_layout";
import IConfig from "../../iconfig";
import { ILayout } from "../../ilayout";
import { ILayoutClass } from "../../ilayout";
import { debug } from "../../util/debug";
export default class KWinConfig implements IConfig {
//#region Layout
public layoutOrder: string[];
public layoutFactories: { [key: string]: () => ILayout };
public maximizeSoleTile: boolean;
public monocleMaximize: boolean;
public monocleMinimizeRest: boolean; // KWin-specific
//#endregion
//#region Features
public adjustLayout: boolean;
public adjustLayoutLive: boolean;
public keepFloatAbove: boolean;
public noTileBorder: boolean;
public limitTileWidthRatio: number;
//#endregion
//#region Gap
public screenGapBottom: number;
public screenGapLeft: number;
public screenGapRight: number;
public screenGapTop: number;
public tileLayoutGap: number;
//#endregion
//#region Behavior
public directionalKeyMode: "dwm" | "focus";
public newWindowAsMaster: boolean;
//#endregion
//#region KWin-specific
public layoutPerActivity: boolean;
public layoutPerDesktop: boolean;
public preventMinimize: boolean;
public preventProtrusion: boolean;
public pollMouseXdotool: boolean;
//#endregion
//#region KWin-specific Rules
public floatUtility: boolean;
public floatingClass: string[];
public floatingTitle: string[];
public ignoreClass: string[];
public ignoreTitle: string[];
public ignoreRole: string[];
public ignoreActivity: string[];
public ignoreScreen: number[];
//#endregion
constructor() {
function commaSeparate(str: string): string[] {
if (!str || typeof str !== "string") return [];
return str.split(",").map((part) => part.trim());
}
DEBUG.enabled = DEBUG.enabled || KWin.readConfig("debug", false);
this.layoutOrder = [];
this.layoutFactories = {};
(
[
["enableTileLayout", true, TileLayout],
["enableMonocleLayout", true, MonocleLayout],
["enableThreeColumnLayout", true, ThreeColumnLayout],
["enableSpreadLayout", true, SpreadLayout],
["enableStairLayout", true, StairLayout],
["enableSpiralLayout", true, SpiralLayout],
["enableQuarterLayout", false, QuarterLayout],
["enableFloatingLayout", false, FloatingLayout],
["enableCascadeLayout", false, CascadeLayout], // TODO: add config
] as Array<[string, boolean, ILayoutClass]>
).forEach(([configKey, defaultValue, layoutClass]) => {
if (KWin.readConfig(configKey, defaultValue))
this.layoutOrder.push(layoutClass.id);
this.layoutFactories[layoutClass.id] = () => new layoutClass();
});
this.maximizeSoleTile = KWin.readConfig("maximizeSoleTile", false);
this.monocleMaximize = KWin.readConfig("monocleMaximize", true);
this.monocleMinimizeRest = KWin.readConfig("monocleMinimizeRest", false);
this.adjustLayout = KWin.readConfig("adjustLayout", true);
this.adjustLayoutLive = KWin.readConfig("adjustLayoutLive", true);
this.keepFloatAbove = KWin.readConfig("keepFloatAbove", true);
this.noTileBorder = KWin.readConfig("noTileBorder", false);
this.limitTileWidthRatio = 0;
if (KWin.readConfig("limitTileWidth", false))
this.limitTileWidthRatio = KWin.readConfig("limitTileWidthRatio", 1.6);
this.screenGapBottom = KWin.readConfig("screenGapBottom", 0);
this.screenGapLeft = KWin.readConfig("screenGapLeft", 0);
this.screenGapRight = KWin.readConfig("screenGapRight", 0);
this.screenGapTop = KWin.readConfig("screenGapTop", 0);
this.tileLayoutGap = KWin.readConfig("tileLayoutGap", 0);
const directionalKeyDwm = KWin.readConfig("directionalKeyDwm", true);
const directionalKeyFocus = KWin.readConfig("directionalKeyFocus", false);
this.directionalKeyMode = directionalKeyDwm ? "dwm" : "focus";
this.newWindowAsMaster = KWin.readConfig("newWindowAsMaster", false);
this.layoutPerActivity = KWin.readConfig("layoutPerActivity", true);
this.layoutPerDesktop = KWin.readConfig("layoutPerDesktop", true);
this.floatUtility = KWin.readConfig("floatUtility", true);
this.preventMinimize = KWin.readConfig("preventMinimize", false);
this.preventProtrusion = KWin.readConfig("preventProtrusion", true);
this.pollMouseXdotool = KWin.readConfig("pollMouseXdotool", false);
this.floatingClass = commaSeparate(KWin.readConfig("floatingClass", ""));
this.floatingTitle = commaSeparate(KWin.readConfig("floatingTitle", ""));
this.ignoreActivity = commaSeparate(KWin.readConfig("ignoreActivity", ""));
this.ignoreClass = commaSeparate(
KWin.readConfig("ignoreClass", "krunner,yakuake,spectacle,kded5")
);
this.ignoreRole = commaSeparate(KWin.readConfig("ignoreRole", "quake"));
this.ignoreScreen = commaSeparate(KWin.readConfig("ignoreScreen", "")).map(
(str) => parseInt(str, 10)
);
this.ignoreTitle = commaSeparate(KWin.readConfig("ignoreTitle", ""));
if (this.preventMinimize && this.monocleMinimizeRest) {
debug(
() => "preventMinimize is disabled because of monocleMinimizeRest."
);
this.preventMinimize = false;
}
}
public toString(): string {
return "Config(" + JSON.stringify(this, undefined, 2) + ")";
}
}

View File

@ -29,7 +29,6 @@ import QuarterLayout from "../../layouts/quarter_layout";
import TilingEngine from "../../engine/tiling_engine";
import TilingController from "../../engine/tiling_controler";
import KWinConfig from "./kwin_config";
import IDriverContext from "../../idriver_context";
import ISurface from "../../isurface";
import Window from "../../engine/window";
@ -42,6 +41,7 @@ import { ILayoutClass } from "../../ilayout";
import { WindowState } from "../../engine/window";
import WrapperMap from "../../util/wrappermap";
import { debug, debugObj } from "../../util/debug";
import IConfig, { Config } from "../../config";
// import { workspace } from "../../extern/global";
/**
@ -66,7 +66,8 @@ export default class KWinDriver implements IDriverContext {
this.kwinApi.workspace.currentActivity,
this.kwinApi.workspace.currentDesktop,
this.qml.activityInfo,
this.kwinApi
this.kwinApi,
this.config
);
}
@ -100,7 +101,8 @@ export default class KWinDriver implements IDriverContext {
this.kwinApi.workspace.currentActivity,
this.kwinApi.workspace.currentDesktop,
this.qml.activityInfo,
this.kwinApi
this.kwinApi,
this.config
)
);
return screens;
@ -120,15 +122,23 @@ export default class KWinDriver implements IDriverContext {
private qml: Bismuth.Qml.Main;
private kwinApi: KWin.Api;
constructor(qmlObjects: Bismuth.Qml.Main, kwinScriptingApi: KWin.Api) {
this.engine = new TilingEngine();
this.control = new TilingController(this.engine);
private config: IConfig;
constructor(qmlObjects: Bismuth.Qml.Main, kwinScriptingApi: KWin.Api, config?: IConfig) {
if (config) {
this.config = config;
} else {
this.config = new Config();
}
this.engine = new TilingEngine(this.config);
this.control = new TilingController(this.engine, this.config);
this.windowMap = new WrapperMap(
(client: KWin.Client) => KWinWindow.generateID(client),
(client: KWin.Client) => new Window(new KWinWindow(client, this.qml, this.kwinApi))
(client: KWin.Client) => new Window(new KWinWindow(client, this.qml, this.kwinApi, this.config), this.config)
);
this.entered = false;
this.mousePoller = new KWinMousePoller(qmlObjects);
this.mousePoller = new KWinMousePoller(qmlObjects, this.config);
this.qml = qmlObjects;
this.kwinApi = kwinScriptingApi;
}
@ -139,21 +149,25 @@ export default class KWinDriver implements IDriverContext {
public main() {
console.log("Initiating systems!");
CONFIG = KWINCONFIG = new KWinConfig();
// debug(() => "Config: " + KWINCONFIG);
// DEBUG = {
// enabled: false,
// started: new Date().getTime(),
// };
// this.bindEvents();
// this.bindShortcut();
// debug(() => "Config: " + this.config);
// const clients = workspace.clientList();
// for (let i = 0; i < clients.length; i++) {
// const window = this.windowMap.add(clients[i]);
// this.engine.manage(window);
// if (window.state !== WindowState.Unmanaged)
// this.bindWindowEvents(window, clients[i]);
// else this.windowMap.remove(clients[i]);
// }
// this.engine.arrange(this);
this.bindEvents();
this.bindShortcut();
const clients = this.kwinApi.workspace.clientList();
for (let i = 0; i < clients.length; i++) {
const window = this.windowMap.add(clients[i]);
this.engine.manage(window);
if (window.state !== WindowState.Unmanaged)
this.bindWindowEvents(window, clients[i]);
else this.windowMap.remove(clients[i]);
}
this.engine.arrange(this);
}
//#region implement methods of IDriverContext`
@ -286,7 +300,8 @@ export default class KWinDriver implements IDriverContext {
this.kwinApi.workspace.currentActivity,
this.kwinApi.workspace.currentDesktop,
this.qml.activityInfo,
this.kwinApi
this.kwinApi,
this.config
);
this.control.onSurfaceUpdate(this, "resized " + srf.toString());
});
@ -353,7 +368,7 @@ export default class KWinDriver implements IDriverContext {
);
this.connect(this.kwinApi.workspace.clientMinimized, (client: KWin.Client) => {
if (KWINCONFIG.preventMinimize) {
if (this.config.preventMinimize) {
client.minimized = false;
this.kwinApi.workspace.activeClient = client;
} else

View File

@ -18,6 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import IConfig from "../../config";
import { KWinSetTimeout } from "./kwin_set_timeout";
export default class KWinMousePoller {
@ -36,11 +37,13 @@ export default class KWinMousePoller {
private startCount: number;
private cmdResult: string | null;
private qml: Bismuth.Qml.Main;
private config: IConfig;
constructor(qml: Bismuth.Qml.Main) {
constructor(qml: Bismuth.Qml.Main, config: IConfig) {
this.startCount = 0;
this.cmdResult = null;
this.qml = qml;
this.config = config;
/* we will poll manually, because this interval value will be
* aligned to intervalAlignment, which probably is 1000. */
@ -59,7 +62,7 @@ export default class KWinMousePoller {
public start() {
this.startCount += 1;
if (KWINCONFIG.pollMouseXdotool)
if (this.config.pollMouseXdotool)
this.qml.mousePoller.connectSource(KWinMousePoller.COMMAND);
}

View File

@ -18,15 +18,16 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import IConfig from "../../config";
import ISurface from "../../isurface";
import { toRect } from "../../util/kwinutil";
import Rect from "../../util/rect";
export default class KWinSurface implements ISurface {
public static generateId(screen: number, activity: string, desktop: number) {
public static generateId(screen: number, activity: string, desktop: number, config: IConfig) {
let path = String(screen);
if (KWINCONFIG.layoutPerActivity) path += "@" + activity;
if (KWINCONFIG.layoutPerDesktop) path += "#" + desktop;
if (config.layoutPerActivity) path += "@" + activity;
if (config.layoutPerDesktop) path += "#" + desktop;
return path;
}
@ -40,17 +41,19 @@ export default class KWinSurface implements ISurface {
private activityInfo: Plasma.TaskManager.ActivityInfo;
private kwinApi: KWin.Api;
private config: IConfig;
constructor(screen: number, activity: string, desktop: number, activityInfo: Plasma.TaskManager.ActivityInfo, kwinApi: KWin.Api) {
constructor(screen: number, activity: string, desktop: number, activityInfo: Plasma.TaskManager.ActivityInfo, kwinApi: KWin.Api, config: IConfig) {
const activityName = activityInfo.activityName(activity);
this.activityInfo = activityInfo;
this.kwinApi = kwinApi;
this.config = config;
this.id = KWinSurface.generateId(screen, activity, desktop);
this.id = KWinSurface.generateId(screen, activity, desktop, this.config);
this.ignore =
KWINCONFIG.ignoreActivity.indexOf(activityName) >= 0 ||
KWINCONFIG.ignoreScreen.indexOf(screen) >= 0;
this.config.ignoreActivity.indexOf(activityName) >= 0 ||
this.config.ignoreScreen.indexOf(screen) >= 0;
this.workingArea = toRect(
this.kwinApi.workspace.clientArea(KWin.PlacementArea, screen, desktop)
);
@ -66,7 +69,7 @@ export default class KWinSurface implements ISurface {
/* TODO: option to create additional desktop */
return null;
return new KWinSurface(this.screen, this.activity, this.desktop + 1, this.activityInfo, this.kwinApi);
return new KWinSurface(this.screen, this.activity, this.desktop + 1, this.activityInfo, this.kwinApi, this.config);
}
public toString(): string {

View File

@ -25,6 +25,7 @@ import Rect from "../../util/rect";
import { toQRect, toRect } from "../../util/kwinutil";
import { clip, matchWords } from "../../util/func";
import { debugObj } from "../../util/debug";
import IConfig from "../../config";
export default class KWinWindow implements IDriverWindow {
public static generateID(client: KWin.Client) {
@ -49,10 +50,10 @@ export default class KWinWindow implements IDriverWindow {
return (
this.client.specialWindow ||
resourceClass === "plasmashell" ||
KWINCONFIG.ignoreClass.indexOf(resourceClass) >= 0 ||
KWINCONFIG.ignoreClass.indexOf(resourceName) >= 0 ||
matchWords(this.client.caption, KWINCONFIG.ignoreTitle) >= 0 ||
KWINCONFIG.ignoreRole.indexOf(windowRole) >= 0
this.config.ignoreClass.indexOf(resourceClass) >= 0 ||
this.config.ignoreClass.indexOf(resourceName) >= 0 ||
matchWords(this.client.caption, this.config.ignoreTitle) >= 0 ||
this.config.ignoreRole.indexOf(windowRole) >= 0
);
}
@ -62,11 +63,11 @@ export default class KWinWindow implements IDriverWindow {
return (
this.client.modal ||
!this.client.resizeable ||
(KWINCONFIG.floatUtility &&
(this.config.floatUtility &&
(this.client.dialog || this.client.splash || this.client.utility)) ||
KWINCONFIG.floatingClass.indexOf(resourceClass) >= 0 ||
KWINCONFIG.floatingClass.indexOf(resourceName) >= 0 ||
matchWords(this.client.caption, KWINCONFIG.floatingTitle) >= 0
this.config.floatingClass.indexOf(resourceClass) >= 0 ||
this.config.floatingClass.indexOf(resourceName) >= 0 ||
matchWords(this.client.caption, this.config.floatingTitle) >= 0
);
}
@ -83,7 +84,7 @@ export default class KWinWindow implements IDriverWindow {
const desktop =
this.client.desktop >= 0 ? this.client.desktop : this.kwinApi.workspace.currentDesktop;
return new KWinSurface(this.client.screen, activity, desktop, this.qml.activityInfo, this.kwinApi);
return new KWinSurface(this.client.screen, activity, desktop, this.qml.activityInfo, this.kwinApi, this.config);
}
public set surface(srf: ISurface) {
@ -99,8 +100,9 @@ export default class KWinWindow implements IDriverWindow {
private noBorderOriginal: boolean;
private qml: Bismuth.Qml.Main;
private kwinApi: KWin.Api;
private config: IConfig;
constructor(client: KWin.Client, qml: Bismuth.Qml.Main, kwinApi: KWin.Api) {
constructor(client: KWin.Client, qml: Bismuth.Qml.Main, kwinApi: KWin.Api, config: IConfig) {
this.client = client;
this.id = KWinWindow.generateID(client);
this.maximized = false;
@ -108,6 +110,7 @@ export default class KWinWindow implements IDriverWindow {
this.noBorderOriginal = client.noBorder;
this.qml = qml;
this.kwinApi = kwinApi;
this.config = config;
}
public commit(geometry?: Rect, noBorder?: boolean, keepAbove?: boolean) {
@ -139,7 +142,7 @@ export default class KWinWindow implements IDriverWindow {
if (geometry !== undefined) {
geometry = this.adjustGeometry(geometry);
if (KWINCONFIG.preventProtrusion) {
if (this.config.preventProtrusion) {
const area = toRect(
this.kwinApi.workspace.clientArea(
KWin.PlacementArea,

View File

@ -22,7 +22,6 @@ import Window from "../../engine/window";
import ISurface from "../../isurface";
import Rect from "../../util/rect";
import TestSurface from "./test_surface";
// import { CONFIG } from "../../config";
export default class TestDriver {
public currentScreen: number;
@ -67,8 +66,3 @@ export default class TestDriver {
setTimeout(func, timeout);
}
}
function setTestConfig(name: string, value: any) {
if (!CONFIG) CONFIG = {} as any;
(CONFIG as any)[name] = value;
}

View File

@ -22,9 +22,9 @@ import MonocleLayout from "../layouts/monocle_layout";
import FloatingLayout from "../layouts/floating_layout";
import { ILayout } from "../ilayout";
// import { CONFIG } from "../config";
import ISurface from "../isurface";
import { wrapIndex } from "../util/func";
import IConfig from "../config";
export class LayoutStoreEntry {
public get currentLayout(): ILayout {
@ -36,9 +36,12 @@ export class LayoutStoreEntry {
private layouts: { [key: string]: ILayout };
private previousID: string;
constructor() {
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.currentIndex = 0;
this.currentID = CONFIG.layoutOrder[0];
this.currentID = this.config.layoutOrder[0];
this.layouts = {};
this.previousID = this.currentID;
@ -49,9 +52,9 @@ export class LayoutStoreEntry {
this.previousID = this.currentID;
this.currentIndex =
this.currentIndex !== null
? wrapIndex(this.currentIndex + step, CONFIG.layoutOrder.length)
? wrapIndex(this.currentIndex + step, this.config.layoutOrder.length)
: 0;
this.currentID = CONFIG.layoutOrder[this.currentIndex];
this.currentID = this.config.layoutOrder[this.currentIndex];
return this.loadLayout(this.currentID);
}
@ -74,13 +77,13 @@ export class LayoutStoreEntry {
}
private updateCurrentIndex(): void {
const idx = CONFIG.layoutOrder.indexOf(this.currentID);
const idx = this.config.layoutOrder.indexOf(this.currentID);
this.currentIndex = idx === -1 ? null : idx;
}
private loadLayout(ID: string): ILayout {
let layout = this.layouts[ID];
if (!layout) layout = this.layouts[ID] = CONFIG.layoutFactories[ID]();
if (!layout) layout = this.layouts[ID] = this.config.layoutFactories[ID]();
return layout;
}
}
@ -88,7 +91,10 @@ export class LayoutStoreEntry {
export default class LayoutStore {
private store: { [key: string]: LayoutStoreEntry };
constructor() {
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.store = {};
}
@ -109,7 +115,7 @@ export default class LayoutStore {
}
private getEntry(key: string): LayoutStoreEntry {
if (!this.store[key]) this.store[key] = new LayoutStoreEntry();
if (!this.store[key]) this.store[key] = new LayoutStoreEntry(this.config);
return this.store[key];
}
}

View File

@ -22,9 +22,9 @@ import TilingEngine from "./tiling_engine";
import IDriverContext from "../idriver_context";
import Window from "./window";
import { WindowState } from "./window";
// import { CONFIG } from "../config";
import { Shortcut } from "../shortcut";
import { debugObj } from "../util/debug";
import IConfig from "../config";
/**
* TilingController translates events to actions, implementing high-level
@ -34,9 +34,11 @@ import { debugObj } from "../util/debug";
*/
export default class TilingController {
private engine: TilingEngine;
private config: IConfig;
public constructor(engine: TilingEngine) {
public constructor(engine: TilingEngine, config: IConfig) {
this.engine = engine;
this.config = config;
}
public onSurfaceUpdate(ctx: IDriverContext, comment: string): void {
@ -128,7 +130,7 @@ export default class TilingController {
public onWindowResize(ctx: IDriverContext, window: Window): void {
debugObj(() => ["onWindowResize", { window }]);
if (CONFIG.adjustLayout && CONFIG.adjustLayoutLive) {
if (this.config.adjustLayout && this.config.adjustLayoutLive) {
if (window.state === WindowState.Tiled) {
this.engine.adjustLayout(window);
this.engine.arrange(ctx);
@ -138,10 +140,10 @@ export default class TilingController {
public onWindowResizeOver(ctx: IDriverContext, window: Window): void {
debugObj(() => ["onWindowResizeOver", { window }]);
if (CONFIG.adjustLayout && window.tiled) {
if (this.config.adjustLayout && window.tiled) {
this.engine.adjustLayout(window);
this.engine.arrange(ctx);
} else if (!CONFIG.adjustLayout) this.engine.enforceSize(ctx, window);
} else if (!this.config.adjustLayout) this.engine.enforceSize(ctx, window);
}
public onWindowMaximizeChanged(
@ -178,7 +180,7 @@ export default class TilingController {
}
public onShortcut(ctx: IDriverContext, input: Shortcut, data?: any) {
if (CONFIG.directionalKeyMode === "focus") {
if (this.config.directionalKeyMode === "focus") {
switch (input) {
case Shortcut.Up:
input = Shortcut.FocusUp;

View File

@ -24,7 +24,6 @@ import LayoutStore from "./layout_store";
import EngineContext from "./engine_context";
import WindowStore from "./window_store";
import Window from "./window";
// import { CONFIG } from "../config";
import IDriverContext from "../idriver_context";
import ISurface from "../isurface";
import { Shortcut } from "../shortcut";
@ -33,6 +32,7 @@ import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
import { debug, debugObj } from "../util/debug";
import { overlap, wrapIndex } from "../util/func";
import IConfig from "../config";
export type Direction = "up" | "down" | "left" | "right";
@ -43,8 +43,11 @@ export default class TilingEngine {
public layouts: LayoutStore;
public windows: WindowStore;
constructor() {
this.layouts = new LayoutStore();
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.layouts = new LayoutStore(this.config);
this.windows = new WindowStore();
}
@ -61,10 +64,10 @@ export default class TilingEngine {
const layout = this.layouts.getCurrentLayout(srf);
if (layout.adjust) {
const area = srf.workingArea.gap(
CONFIG.screenGapLeft,
CONFIG.screenGapRight,
CONFIG.screenGapTop,
CONFIG.screenGapBottom
this.config.screenGapLeft,
this.config.screenGapRight,
this.config.screenGapTop,
this.config.screenGapBottom
);
const tiles = this.windows.getVisibleTiles(srf);
layout.adjust(area, tiles, basis, basis.geometryDelta);
@ -165,10 +168,10 @@ export default class TilingEngine {
const layout = this.layouts.getCurrentLayout(srf);
if (layout.adjust) {
const area = srf.workingArea.gap(
CONFIG.screenGapLeft,
CONFIG.screenGapRight,
CONFIG.screenGapTop,
CONFIG.screenGapBottom
this.config.screenGapLeft,
this.config.screenGapRight,
this.config.screenGapTop,
this.config.screenGapBottom
);
layout.adjust(area, this.windows.getVisibleTileables(srf), basis, delta);
}
@ -211,14 +214,14 @@ export default class TilingEngine {
const workingArea = srf.workingArea;
let tilingArea: Rect;
if (CONFIG.monocleMaximize && layout instanceof MonocleLayout)
if (this.config.monocleMaximize && layout instanceof MonocleLayout)
tilingArea = workingArea;
else
tilingArea = workingArea.gap(
CONFIG.screenGapLeft,
CONFIG.screenGapRight,
CONFIG.screenGapTop,
CONFIG.screenGapBottom
this.config.screenGapLeft,
this.config.screenGapRight,
this.config.screenGapTop,
this.config.screenGapBottom
);
const visibles = this.windows.getVisibleWindows(srf);
@ -239,15 +242,15 @@ export default class TilingEngine {
});
const tileables = this.windows.getVisibleTileables(srf);
if (CONFIG.maximizeSoleTile && tileables.length === 1) {
if (this.config.maximizeSoleTile && tileables.length === 1) {
tileables[0].state = WindowState.Maximized;
tileables[0].geometry = workingArea;
} else if (tileables.length > 0)
layout.apply(new EngineContext(ctx, this), tileables, tilingArea);
if (CONFIG.limitTileWidthRatio > 0 && !(layout instanceof MonocleLayout)) {
if (this.config.limitTileWidthRatio > 0 && !(layout instanceof MonocleLayout)) {
const maxWidth = Math.floor(
workingArea.height * CONFIG.limitTileWidthRatio
workingArea.height * this.config.limitTileWidthRatio
);
tileables
.filter((tile) => tile.tiled && tile.geometry.width > maxWidth)
@ -287,7 +290,7 @@ export default class TilingEngine {
if (!window.shouldIgnore) {
/* engine#arrange will update the state when required. */
window.state = WindowState.Undecided;
if (CONFIG.newWindowAsMaster) this.windows.unshift(window);
if (this.config.newWindowAsMaster) this.windows.unshift(window);
else this.windows.push(window);
}
}

View File

@ -18,12 +18,12 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import IConfig from "../config";
import IDriverWindow from "../idriver_window";
import ISurface from "../isurface";
import { debugObj } from "../util/debug";
import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
// import { CONFIG } from "../config";
export enum WindowState {
/* initial value */
@ -153,7 +153,11 @@ export default class Window {
private shouldCommitFloat: boolean;
private weightMap: { [key: string]: number };
constructor(window: IDriverWindow) {
private config: IConfig;
constructor(window: IDriverWindow, config: IConfig) {
this.config = config;
this.id = window.id;
this.window = window;
@ -180,7 +184,7 @@ export default class Window {
case WindowState.Floating:
if (!this.shouldCommitFloat) break;
this.window.commit(this.floatGeometry, false, CONFIG.keepFloatAbove);
this.window.commit(this.floatGeometry, false, this.config.keepFloatAbove);
this.shouldCommitFloat = false;
break;
@ -189,12 +193,12 @@ export default class Window {
break;
case WindowState.Tiled:
this.window.commit(this.geometry, CONFIG.noTileBorder, false);
this.window.commit(this.geometry, this.config.noTileBorder, false);
break;
case WindowState.TiledAfloat:
if (!this.shouldCommitFloat) break;
this.window.commit(this.floatGeometry, false, CONFIG.keepFloatAbove);
this.window.commit(this.floatGeometry, false, this.config.keepFloatAbove);
this.shouldCommitFloat = false;
break;
}

View File

@ -1,51 +0,0 @@
// Copyright (c) 2018-2019 Eon S. Jeon <esjeon@hyunmu.am>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import { ILayout } from "./ilayout";
export default interface IConfig {
//#region Layout
layoutOrder: string[];
layoutFactories: { [key: string]: () => ILayout };
monocleMaximize: boolean;
maximizeSoleTile: boolean;
//#endregion
//#region Features
adjustLayout: boolean;
adjustLayoutLive: boolean;
keepFloatAbove: boolean;
noTileBorder: boolean;
limitTileWidthRatio: number;
//#endregion
//#region Gap
screenGapBottom: number;
screenGapLeft: number;
screenGapRight: number;
screenGapTop: number;
tileLayoutGap: number;
//#endregion
//#region Behavior
directionalKeyMode: "dwm" | "focus";
newWindowAsMaster: boolean;
//#endregion
}

View File

@ -23,10 +23,11 @@ import { Shortcut } from "./shortcut";
import Window from "./engine/window";
import Rect from "./util/rect";
import RectDelta from "./util/rectdelta";
import IConfig from "./config";
export interface ILayoutClass {
readonly id: string;
new(): ILayout;
new(config: IConfig): ILayout;
}
export interface ILayout {

View File

@ -18,10 +18,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import IConfig from "../config";
import Window from "../engine/window";
import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
// import { CONFIG } from "../config";
import LayoutUtils from "./layout_utils";
export interface ILayoutPart {
@ -182,7 +182,10 @@ export class HalfSplitLayoutPart<L extends ILayoutPart, R extends ILayoutPart>
export class StackLayoutPart implements ILayoutPart {
public gap: number;
constructor() {
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.gap = 0;
}
@ -195,7 +198,7 @@ export class StackLayoutPart implements ILayoutPart {
const weights = LayoutUtils.adjustAreaWeights(
area,
tiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
tiles.indexOf(basis),
delta,
false

View File

@ -22,11 +22,11 @@ import EngineContext from "../engine/engine_context";
import KWinDriver from "../driver/kwin/kwin_driver";
import KWinWindow from "../driver/kwin/kwin_window";
import Window from "../engine/window";
// import { CONFIG } from "../config";
import { ILayout } from "../ilayout";
import { Shortcut } from "../shortcut";
import { WindowState } from "../engine/window";
import Rect from "../util/rect";
import IConfig from "../config";
export default class MonocleLayout implements ILayout {
public static readonly id = "MonocleLayout";
@ -34,10 +34,16 @@ export default class MonocleLayout implements ILayout {
public readonly classID = MonocleLayout.id;
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
}
public apply(ctx: EngineContext, tileables: Window[], area: Rect): void {
/* Tile all tileables */
tileables.forEach((tile) => {
tile.state = CONFIG.monocleMaximize
tile.state = this.config.monocleMaximize
? WindowState.Maximized
: WindowState.Tiled;
tile.geometry = area;
@ -46,7 +52,7 @@ export default class MonocleLayout implements ILayout {
/* KWin-specific `monocleMinimizeRest` option */
if (
ctx.backend === KWinDriver.backendName &&
KWINCONFIG.monocleMinimizeRest
this.config.monocleMinimizeRest
) {
const tiles = [...tileables];
ctx.setTimeout(() => {

View File

@ -25,7 +25,7 @@ import { WindowState } from "../engine/window";
import { clip } from "../util/func";
import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
// import { CONFIG } from "../config";
import IConfig from "../config";
export default class QuarterLayout implements ILayout {
public static readonly MAX_PROPORTION = 0.8;
@ -42,10 +42,14 @@ export default class QuarterLayout implements ILayout {
private rhsplit: number;
private vsplit: number;
public constructor() {
private config: IConfig;
public constructor(config: IConfig) {
this.lhsplit = 0.5;
this.rhsplit = 0.5;
this.vsplit = 0.5;
this.config = config;
}
public adjust(area: Rect, tiles: Window[], basis: Window, delta: RectDelta) {
@ -101,7 +105,7 @@ export default class QuarterLayout implements ILayout {
}
public clone(): ILayout {
const other = new QuarterLayout();
const other = new QuarterLayout(this.config);
other.lhsplit = this.lhsplit;
other.rhsplit = this.rhsplit;
other.vsplit = this.vsplit;
@ -122,8 +126,8 @@ export default class QuarterLayout implements ILayout {
return;
}
const gap1 = Math.floor(CONFIG.tileLayoutGap / 2);
const gap2 = CONFIG.tileLayoutGap - gap1;
const gap1 = Math.floor(this.config.tileLayoutGap / 2);
const gap2 = this.config.tileLayoutGap - gap1;
const leftWidth = Math.floor(area.width * this.vsplit);
const rightWidth = area.width - leftWidth;

View File

@ -22,11 +22,11 @@ import EngineContext from "../engine/engine_context";
import { HalfSplitLayoutPart } from "./layout_part";
import { FillLayoutPart } from "./layout_part";
import { ILayout } from "../ilayout";
// import { CONFIG } from "../config";
import Window from "../engine/window";
import { WindowState } from "../engine/window";
import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
import IConfig from "../config";
export type SpiralLayoutPart = HalfSplitLayoutPart<
FillLayoutPart,
@ -39,14 +39,18 @@ export default class SpiralLayout implements ILayout {
private depth: number;
private parts: SpiralLayoutPart;
constructor() {
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.depth = 1;
this.parts = new HalfSplitLayoutPart(
new FillLayoutPart(),
new FillLayoutPart()
);
this.parts.angle = 0;
this.parts.gap = CONFIG.tileLayoutGap;
this.parts.gap = this.config.tileLayoutGap;
}
public adjust(
@ -87,7 +91,7 @@ export default class SpiralLayout implements ILayout {
let npart: SpiralLayoutPart;
while (i < depth - 1) {
npart = new HalfSplitLayoutPart(new FillLayoutPart(), lastFillPart);
npart.gap = CONFIG.tileLayoutGap;
npart.gap = this.config.tileLayoutGap;
switch ((i + 1) % 4) {
case 0:
npart.angle = 0;

View File

@ -21,13 +21,13 @@
import EngineContext from "../engine/engine_context";
import { ILayout } from "../ilayout";
import Window from "../engine/window";
// import { CONFIG } from "../config";
import LayoutUtils from "./layout_utils";
import { Shortcut } from "../shortcut";
import { WindowState } from "../engine/window";
import { partitionArrayBySizes, clip, slide } from "../util/func";
import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
import IConfig from "../config";
export default class ThreeColumnLayout implements ILayout {
public static readonly MIN_MASTER_RATIO = 0.2;
@ -43,7 +43,10 @@ export default class ThreeColumnLayout implements ILayout {
private masterRatio: number;
private masterSize: number;
constructor() {
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.masterRatio = 0.6;
this.masterSize = 1;
}
@ -65,7 +68,7 @@ export default class ThreeColumnLayout implements ILayout {
LayoutUtils.adjustAreaWeights(
area,
tiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
tiles.indexOf(basis),
delta
).forEach((newWeight, i) => (tiles[i].weight = newWeight * tiles.length));
@ -76,7 +79,7 @@ export default class ThreeColumnLayout implements ILayout {
this.masterRatio = LayoutUtils.adjustAreaHalfWeights(
area,
this.masterRatio,
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
basisIndex < this.masterSize ? 0 : 1,
delta,
true
@ -88,7 +91,7 @@ export default class ThreeColumnLayout implements ILayout {
LayoutUtils.adjustAreaWeights(
area,
masterTiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
basisIndex,
delta
).forEach(
@ -111,7 +114,7 @@ export default class ThreeColumnLayout implements ILayout {
const newRatios = LayoutUtils.adjustAreaWeights(
area,
[stackRatio, this.masterRatio, stackRatio],
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
basisGroup,
delta,
true
@ -128,7 +131,7 @@ export default class ThreeColumnLayout implements ILayout {
LayoutUtils.adjustAreaWeights(
area /* we only need height */,
groupTiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
groupTiles.indexOf(basis),
delta
).forEach(
@ -147,14 +150,14 @@ export default class ThreeColumnLayout implements ILayout {
LayoutUtils.splitAreaWeighted(
area,
tiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap
this.config.tileLayoutGap
).forEach((tileArea, i) => (tiles[i].geometry = tileArea));
} else if (tiles.length === this.masterSize + 1) {
/* master & R-stack (only 1 window in stack) */
const [masterArea, stackArea] = LayoutUtils.splitAreaHalfWeighted(
area,
this.masterRatio,
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
true
);
@ -162,7 +165,7 @@ export default class ThreeColumnLayout implements ILayout {
LayoutUtils.splitAreaWeighted(
masterArea,
masterTiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap
this.config.tileLayoutGap
).forEach((tileArea, i) => (masterTiles[i].geometry = tileArea));
tiles[tiles.length - 1].geometry = stackArea;
@ -174,7 +177,7 @@ export default class ThreeColumnLayout implements ILayout {
const groupAreas = LayoutUtils.splitAreaWeighted(
area,
[stackRatio, this.masterRatio, stackRatio],
CONFIG.tileLayoutGap,
this.config.tileLayoutGap,
true
);
@ -185,14 +188,14 @@ export default class ThreeColumnLayout implements ILayout {
LayoutUtils.splitAreaWeighted(
groupAreas[group],
groupTiles.map((tile) => tile.weight),
CONFIG.tileLayoutGap
this.config.tileLayoutGap
).forEach((tileArea, i) => (groupTiles[i].geometry = tileArea));
});
}
}
public clone(): ILayout {
const other = new ThreeColumnLayout();
const other = new ThreeColumnLayout(this.config);
other.masterRatio = this.masterRatio;
other.masterSize = this.masterSize;
return other;

View File

@ -20,7 +20,6 @@
import EngineContext from "../engine/engine_context";
import { ILayout } from "../ilayout";
// import { CONFIG } from "../config";
import Window from "../engine/window";
import { WindowState } from "../engine/window";
import { Shortcut } from "../shortcut";
@ -29,6 +28,7 @@ import { RotateLayoutPart, HalfSplitLayoutPart, StackLayoutPart } from "./layout
import { clip, slide } from "../util/func";
import Rect from "../util/rect";
import RectDelta from "../util/rectdelta";
import IConfig from "../config";
export default class TileLayout implements ILayout {
public static readonly MIN_MASTER_RATIO = 0.2;
@ -61,11 +61,15 @@ export default class TileLayout implements ILayout {
this.parts.inner.ratio = value;
}
constructor() {
private config: IConfig;
constructor(config: IConfig) {
this.config = config;
this.parts = new RotateLayoutPart(
new HalfSplitLayoutPart(
new RotateLayoutPart(new StackLayoutPart()),
new StackLayoutPart()
new RotateLayoutPart(new StackLayoutPart(this.config)),
new StackLayoutPart(this.config)
)
);
@ -73,7 +77,7 @@ export default class TileLayout implements ILayout {
masterPart.gap =
masterPart.primary.inner.gap =
masterPart.secondary.gap =
CONFIG.tileLayoutGap;
this.config.tileLayoutGap;
}
public adjust(area: Rect, tiles: Window[], basis: Window, delta: RectDelta) {
@ -89,7 +93,7 @@ export default class TileLayout implements ILayout {
}
public clone(): ILayout {
const other = new TileLayout();
const other = new TileLayout(this.config);
other.masterRatio = this.masterRatio;
other.numMaster = this.numMaster;
return other;