"use strict"; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var Shortcut; (function (Shortcut) { Shortcut[Shortcut["FocusNext"] = 0] = "FocusNext"; Shortcut[Shortcut["FocusPrev"] = 1] = "FocusPrev"; Shortcut[Shortcut["DWMLeft"] = 2] = "DWMLeft"; Shortcut[Shortcut["DWMRight"] = 3] = "DWMRight"; Shortcut[Shortcut["FocusUp"] = 4] = "FocusUp"; Shortcut[Shortcut["FocusDown"] = 5] = "FocusDown"; Shortcut[Shortcut["FocusLeft"] = 6] = "FocusLeft"; Shortcut[Shortcut["FocusRight"] = 7] = "FocusRight"; Shortcut[Shortcut["ShiftLeft"] = 8] = "ShiftLeft"; Shortcut[Shortcut["ShiftRight"] = 9] = "ShiftRight"; Shortcut[Shortcut["ShiftUp"] = 10] = "ShiftUp"; Shortcut[Shortcut["ShiftDown"] = 11] = "ShiftDown"; Shortcut[Shortcut["SwapUp"] = 12] = "SwapUp"; Shortcut[Shortcut["SwapDown"] = 13] = "SwapDown"; Shortcut[Shortcut["SwapLeft"] = 14] = "SwapLeft"; Shortcut[Shortcut["SwapRight"] = 15] = "SwapRight"; Shortcut[Shortcut["GrowWidth"] = 16] = "GrowWidth"; Shortcut[Shortcut["GrowHeight"] = 17] = "GrowHeight"; Shortcut[Shortcut["ShrinkWidth"] = 18] = "ShrinkWidth"; Shortcut[Shortcut["ShrinkHeight"] = 19] = "ShrinkHeight"; Shortcut[Shortcut["Increase"] = 20] = "Increase"; Shortcut[Shortcut["Decrease"] = 21] = "Decrease"; Shortcut[Shortcut["ShiftIncrease"] = 22] = "ShiftIncrease"; Shortcut[Shortcut["ShiftDecrease"] = 23] = "ShiftDecrease"; Shortcut[Shortcut["ToggleFloat"] = 24] = "ToggleFloat"; Shortcut[Shortcut["ToggleFloatAll"] = 25] = "ToggleFloatAll"; Shortcut[Shortcut["SetMaster"] = 26] = "SetMaster"; Shortcut[Shortcut["NextLayout"] = 27] = "NextLayout"; Shortcut[Shortcut["PreviousLayout"] = 28] = "PreviousLayout"; Shortcut[Shortcut["SetLayout"] = 29] = "SetLayout"; Shortcut[Shortcut["Rotate"] = 30] = "Rotate"; Shortcut[Shortcut["RotatePart"] = 31] = "RotatePart"; })(Shortcut || (Shortcut = {})); var CONFIG; var KWinConfig = (function () { function KWinConfig() { var _this = this; function commaSeparate(str) { if (!str || typeof str !== "string") return []; return str .split(",") .map(function (part) { return part.trim(); }) .filter(function (part) { return part != ""; }); } 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], ["enableStackedLayout", false, StackedLayout], ["enableFloatingLayout", false, FloatingLayout], ["enableBTreeLayout", false, BTreeLayout], ["enableCascadeLayout", false, CascadeLayout], ].forEach(function (_a) { var configKey = _a[0], defaultValue = _a[1], layoutClass = _a[2]; if (KWIN.readConfig(configKey, defaultValue)) _this.layoutOrder.push(layoutClass.id); _this.layoutFactories[layoutClass.id] = function () { return new layoutClass(); }; }); this.maximizeSoleTile = KWIN.readConfig("maximizeSoleTile", false); this.monocleMaximize = KWIN.readConfig("monocleMaximize", true); this.monocleMinimizeRest = KWIN.readConfig("monocleMinimizeRest", false); this.stairReverse = KWIN.readConfig("stairReverse", false); this.adjustLayout = KWIN.readConfig("adjustLayout", true); this.adjustLayoutLive = KWIN.readConfig("adjustLayoutLive", true); this.keepFloatAbove = KWIN.readConfig("keepFloatAbove", true); this.keepTilingOnDrag = KWIN.readConfig("keepTilingOnDrag", false); 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); var directionalKeyDwm = KWIN.readConfig("directionalKeyDwm", false); var directionalKeyFocus = KWIN.readConfig("directionalKeyFocus", true); this.directionalKeyMode = directionalKeyDwm ? "dwm" : "focus"; this.newWindowPosition = KWIN.readConfig("newWindowPosition", 0); 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,xwaylandvideobridge,plasmashell,ksplashqml")); this.ignoreRole = commaSeparate(KWIN.readConfig("ignoreRole", "quake")); this.ignoreScreen = commaSeparate(KWIN.readConfig("ignoreScreen", "")); this.ignoreTitle = commaSeparate(KWIN.readConfig("ignoreTitle", "")); this.screenDefaultLayout = commaSeparate(KWIN.readConfig("screenDefaultLayout", "")); if (this.preventMinimize && this.monocleMinimizeRest) { debug(function () { return "preventMinimize is disabled because of monocleMinimizeRest."; }); this.preventMinimize = false; } } KWinConfig.prototype.toString = function () { return "Config(" + JSON.stringify(this, undefined, 2) + ")"; }; return KWinConfig; }()); var KWINCONFIG; var KWIN; var KWinDriver = (function () { function KWinDriver(api) { var _this = this; KWIN = api.kwin; this.workspace = api.workspace; this.shortcuts = api.shortcuts; this.engine = new TilingEngine(); this.control = new TilingController(this.engine); this.windowMap = new WrapperMap(function (client) { return KWinWindow.generateID(client); }, function (client) { return new WindowClass(new KWinWindow(client, _this.workspace)); }); this.entered = false; this.mousePoller = new KWinMousePoller(); } Object.defineProperty(KWinDriver.prototype, "backend", { get: function () { return KWinDriver.backendName; }, enumerable: false, configurable: true }); Object.defineProperty(KWinDriver.prototype, "currentSurface", { get: function () { return new KWinSurface(this.workspace.activeWindow ? this.workspace.activeWindow.output : this.workspace.activeScreen, this.workspace.currentActivity, this.workspace.currentDesktop, this.workspace); }, set: function (value) { var ksrf = value; if (this.workspace.currentDesktop.name !== ksrf.desktop.name) this.workspace.currentDesktop = ksrf.desktop; if (this.workspace.currentActivity !== ksrf.activity) this.workspace.currentActivity = ksrf.activity; }, enumerable: false, configurable: true }); Object.defineProperty(KWinDriver.prototype, "currentWindow", { get: function () { var client = this.workspace.activeWindow; return client ? this.windowMap.get(client) : null; }, set: function (window) { if (window !== null) this.workspace.activeWindow = window.window.window; }, enumerable: false, configurable: true }); Object.defineProperty(KWinDriver.prototype, "screens", { get: function () { var _this = this; var screens = []; this.workspace.screens.forEach(function (screen) { screens.push(new KWinSurface(screen, _this.workspace.currentActivity, _this.workspace.currentDesktop, _this.workspace)); }); return screens; }, enumerable: false, configurable: true }); Object.defineProperty(KWinDriver.prototype, "cursorPosition", { get: function () { return this.mousePoller.mousePosition; }, enumerable: false, configurable: true }); KWinDriver.prototype.main = function () { CONFIG = KWINCONFIG = new KWinConfig(); debug(function () { return "Config: " + KWINCONFIG; }); this.bindEvents(); this.bindShortcut(); var clients = this.workspace.stackingOrder; for (var i = 0; i < clients.length; i++) { this.addWindow(clients[i]); } }; KWinDriver.prototype.addWindow = function (client) { if (client.normalWindow && !client.hidden && client.width * client.height > 10) { if (KWIN.readConfig("debugActiveWin", false)) print(debugWin(client)); var window = this.windowMap.add(client); this.control.onWindowAdded(this, window); if (window.state !== WindowState.Unmanaged) { this.bindWindowEvents(window, client); } else { this.windowMap.remove(client); if (KWIN.readConfig("debugActiveWin", false)) print("Unmanaged: " + debugWin(client)); } } else { if (KWIN.readConfig("debugActiveWin", false)) print("Filtered: " + debugWin(client)); } }; KWinDriver.prototype.setTimeout = function (func, timeout) { var _this = this; KWinSetTimeout(function () { return _this.enter(func); }, timeout); }; KWinDriver.prototype.showNotification = function (text) { popupDialog.show(text); }; KWinDriver.prototype.bindShortcut = function () { var _this = this; var callbackShortcut = function (shortcut) { return function () { _this.enter(function () { return _this.control.onShortcut(_this, shortcut); }); }; }; this.shortcuts .getFocusNext() .activated.connect(callbackShortcut(Shortcut.FocusNext)); this.shortcuts .getFocusPrev() .activated.connect(callbackShortcut(Shortcut.FocusPrev)); this.shortcuts .getFocusDown() .activated.connect(callbackShortcut(Shortcut.FocusDown)); this.shortcuts .getFocusUp() .activated.connect(callbackShortcut(Shortcut.FocusUp)); this.shortcuts .getFocusLeft() .activated.connect(callbackShortcut(Shortcut.FocusLeft)); this.shortcuts .getFocusRight() .activated.connect(callbackShortcut(Shortcut.FocusRight)); this.shortcuts .getShiftDown() .activated.connect(callbackShortcut(Shortcut.ShiftDown)); this.shortcuts .getShiftUp() .activated.connect(callbackShortcut(Shortcut.ShiftUp)); this.shortcuts .getShiftLeft() .activated.connect(callbackShortcut(Shortcut.ShiftLeft)); this.shortcuts .getShiftRight() .activated.connect(callbackShortcut(Shortcut.ShiftRight)); this.shortcuts .getGrowHeight() .activated.connect(callbackShortcut(Shortcut.GrowHeight)); this.shortcuts .getShrinkHeight() .activated.connect(callbackShortcut(Shortcut.ShrinkHeight)); this.shortcuts .getShrinkWidth() .activated.connect(callbackShortcut(Shortcut.ShrinkWidth)); this.shortcuts .getGrowWidth() .activated.connect(callbackShortcut(Shortcut.GrowWidth)); this.shortcuts .getIncrease() .activated.connect(callbackShortcut(Shortcut.Increase)); this.shortcuts .getDecrease() .activated.connect(callbackShortcut(Shortcut.Decrease)); this.shortcuts .getToggleFloat() .activated.connect(callbackShortcut(Shortcut.ToggleFloat)); this.shortcuts .getFloatAll() .activated.connect(callbackShortcut(Shortcut.ToggleFloatAll)); this.shortcuts .getNextLayout() .activated.connect(callbackShortcut(Shortcut.NextLayout)); this.shortcuts .getPreviousLayout() .activated.connect(callbackShortcut(Shortcut.PreviousLayout)); this.shortcuts .getRotate() .activated.connect(callbackShortcut(Shortcut.Rotate)); this.shortcuts .getRotatePart() .activated.connect(callbackShortcut(Shortcut.RotatePart)); this.shortcuts .getSetMaster() .activated.connect(callbackShortcut(Shortcut.SetMaster)); var callbackShortcutLayout = function (layoutClass) { return function () { _this.enter(function () { return _this.control.onShortcut(_this, Shortcut.SetLayout, layoutClass.id); }); }; }; this.shortcuts .getTileLayout() .activated.connect(callbackShortcutLayout(TileLayout)); this.shortcuts .getMonocleLayout() .activated.connect(callbackShortcutLayout(MonocleLayout)); this.shortcuts .getThreeColumnLayout() .activated.connect(callbackShortcutLayout(ThreeColumnLayout)); this.shortcuts .getSpreadLayout() .activated.connect(callbackShortcutLayout(SpreadLayout)); this.shortcuts .getStairLayout() .activated.connect(callbackShortcutLayout(StairLayout)); this.shortcuts .getFloatingLayout() .activated.connect(callbackShortcutLayout(FloatingLayout)); this.shortcuts .getQuarterLayout() .activated.connect(callbackShortcutLayout(QuarterLayout)); this.shortcuts .getStackedLayout() .activated.connect(callbackShortcutLayout(StackedLayout)); this.shortcuts .getSpiralLayout() .activated.connect(callbackShortcutLayout(SpiralLayout)); this.shortcuts .getBTreeLayout() .activated.connect(callbackShortcutLayout(BTreeLayout)); }; KWinDriver.prototype.connect = function (signal, handler) { var _this = this; var wrapper = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (typeof _this.workspace === "undefined") signal.disconnect(wrapper); else _this.enter(function () { return handler.apply(_this, args); }); }; signal.connect(wrapper); return wrapper; }; KWinDriver.prototype.enter = function (callback) { if (this.entered) return; this.entered = true; try { callback(); } catch (e) { debug(function () { return "Error raised from line " + e.lineNumber; }); debug(function () { return e; }); } finally { this.entered = false; } }; KWinDriver.prototype.bindEvents = function () { var _this = this; this.connect(this.workspace.screensChanged, function () { return _this.control.onSurfaceUpdate(_this, "screens (Outputs) changed"); }); this.connect(this.workspace.virtualScreenGeometryChanged, function () { _this.control.onSurfaceUpdate(_this, "virtualScreenGeometryChanged"); }); this.connect(this.workspace.currentActivityChanged, function (activityId) { return _this.control.onCurrentActivityChanged(_this, activityId); }); this.connect(this.workspace.currentDesktopChanged, function (virtualDesktop) { return _this.control.onSurfaceUpdate(_this, "currentDesktopChanged"); }); this.connect(this.workspace.windowAdded, function (client) { _this.addWindow(client); }); this.connect(this.workspace.windowRemoved, function (client) { var window = _this.windowMap.get(client); if (window) { _this.control.onWindowRemoved(_this, window); _this.windowMap.remove(client); } }); }; KWinDriver.prototype.bindWindowEvents = function (window, client) { var _this = this; var moving = false; var resizing = false; this.connect(client.maximizedAboutToChange, function (mode) { var maximized = mode === 3; window.window.maximized = maximized; _this.control.onWindowMaximizeChanged(_this, window, maximized); }); this.connect(client.minimizedChanged, function () { if (KWINCONFIG.preventMinimize) { client.minimized = false; _this.workspace.activeWindow = client; } else { var comment = client.minimized ? "minimized" : "unminimized"; _this.control.onWindowChanged(_this, window, comment); } }); this.connect(client.fullScreenChanged, function () { return _this.control.onWindowChanged(_this, window, "fullscreen=" + client.fullScreen); }); this.connect(client.moveResizedChanged, function () { debugObj(function () { return [ "moveResizedChanged", { window: window, move: client.move, resize: client.resize }, ]; }); if (moving !== client.move) { moving = client.move; if (moving) { _this.mousePoller.start(); _this.control.onWindowMoveStart(window); } else { _this.control.onWindowMoveOver(_this, window); _this.mousePoller.stop(); } } if (resizing !== client.resize) { resizing = client.resize; if (resizing) _this.control.onWindowResizeStart(window); else _this.control.onWindowResizeOver(_this, window); } }); this.connect(client.bufferGeometryChanged, function () { if (moving) _this.control.onWindowMove(window); else if (resizing) _this.control.onWindowResize(_this, window); else { if (!window.actualGeometry.equals(window.geometry)) _this.control.onWindowGeometryChanged(_this, window); } }); this.connect(client.activeChanged, function () { if (client.active) _this.control.onWindowFocused(_this, window); }); this.connect(client.outputChanged, function () { return _this.control.onWindowChanged(_this, window, "screen=" + client.output.name); }); this.connect(client.activitiesChanged, function () { return _this.control.onWindowChanged(_this, window, "activity=" + client.activities.join(",")); }); this.connect(client.desktopsChanged, function () { return _this.control.onWindowChanged(_this, window, "Window's desktop changed."); }); }; KWinDriver.backendName = "kwin"; return KWinDriver; }()); var KWinMousePoller = (function () { function KWinMousePoller() { var _this = this; this.startCount = 0; this.cmdResult = null; mousePoller.interval = 0; mousePoller.onNewData.connect(function (sourceName, data) { _this.cmdResult = data["exit code"] === 0 ? data["stdout"] : null; mousePoller.disconnectSource(KWinMousePoller.COMMAND); KWinSetTimeout(function () { if (_this.started) mousePoller.connectSource(KWinMousePoller.COMMAND); }, KWinMousePoller.INTERVAL); }); } Object.defineProperty(KWinMousePoller.prototype, "started", { get: function () { return this.startCount > 0; }, enumerable: false, configurable: true }); Object.defineProperty(KWinMousePoller.prototype, "mousePosition", { get: function () { return this.parseResult(); }, enumerable: false, configurable: true }); KWinMousePoller.prototype.start = function () { this.startCount += 1; if (KWINCONFIG.pollMouseXdotool) mousePoller.connectSource(KWinMousePoller.COMMAND); }; KWinMousePoller.prototype.stop = function () { this.startCount = Math.max(this.startCount - 1, 0); }; KWinMousePoller.prototype.parseResult = function () { if (!this.cmdResult) return null; var x = null; var y = null; this.cmdResult .split(" ") .slice(0, 2) .forEach(function (part) { var _a = part.split(":"), key = _a[0], value = _a[1], _ = _a[2]; if (key === "x") x = parseInt(value, 10); if (key === "y") y = parseInt(value, 10); }); if (x === null || y === null) return null; return [x, y]; }; KWinMousePoller.COMMAND = "xdotool getmouselocation"; KWinMousePoller.INTERVAL = 50; return KWinMousePoller; }()); var KWinTimerPool = (function () { function KWinTimerPool() { this.timers = []; this.numTimers = 0; } KWinTimerPool.prototype.setTimeout = function (func, timeout) { var _this = this; if (this.timers.length === 0) { this.numTimers++; debugObj(function () { return ["setTimeout/newTimer", { numTimers: _this.numTimers }]; }); } var timer = this.timers.pop() || Qt.createQmlObject("import QtQuick 2.0; Timer {}", scriptRoot); var callback = function () { try { timer.triggered.disconnect(callback); } catch (e) { } try { func(); } catch (e) { } _this.timers.push(timer); }; timer.interval = timeout; timer.repeat = false; timer.triggered.connect(callback); timer.start(); }; KWinTimerPool.instance = new KWinTimerPool(); return KWinTimerPool; }()); function KWinSetTimeout(func, timeout) { KWinTimerPool.instance.setTimeout(func, timeout); } var KWinSurface = (function () { function KWinSurface(output, activity, desktop, workspace) { this.id = KWinSurface.generateId(output.name, activity, desktop.name); this.ignore = KWINCONFIG.ignoreActivity.indexOf(activity) >= 0 || KWINCONFIG.ignoreScreen.indexOf(output.name) >= 0; this.workingArea = toRect(workspace.clientArea(0, output, desktop)); this.output = output; this.activity = activity; this.desktop = desktop; } KWinSurface.generateId = function (screenName, activity, desktopName) { var path = screenName; if (KWINCONFIG.layoutPerActivity) path += "@" + activity; if (KWINCONFIG.layoutPerDesktop) path += "#" + desktopName; return path; }; KWinSurface.prototype.next = function () { return null; }; KWinSurface.prototype.toString = function () { return ("KWinSurface(" + [this.output.name, this.activity, this.desktop.name].join(", ") + ")"); }; return KWinSurface; }()); var KWinWindow = (function () { function KWinWindow(window, workspace) { this.workspace = workspace; this.window = window; this.id = KWinWindow.generateID(window); this.maximized = false; this.noBorderManaged = false; this.noBorderOriginal = window.noBorder; } KWinWindow.generateID = function (w) { return w.internalId.toString(); }; Object.defineProperty(KWinWindow.prototype, "fullScreen", { get: function () { return this.window.fullScreen; }, enumerable: false, configurable: true }); Object.defineProperty(KWinWindow.prototype, "geometry", { get: function () { return toRect(this.window.bufferGeometry); }, enumerable: false, configurable: true }); Object.defineProperty(KWinWindow.prototype, "shouldIgnore", { get: function () { var resourceClass = String(this.window.resourceClass); var resourceName = String(this.window.resourceName); var windowRole = String(this.window.windowRole); return (this.window.specialWindow || resourceClass === "plasmashell" || KWINCONFIG.ignoreClass.indexOf(resourceClass) >= 0 || KWINCONFIG.ignoreClass.indexOf(resourceName) >= 0 || matchWords(this.window.caption, KWINCONFIG.ignoreTitle) >= 0 || KWINCONFIG.ignoreRole.indexOf(windowRole) >= 0); }, enumerable: false, configurable: true }); Object.defineProperty(KWinWindow.prototype, "shouldFloat", { get: function () { var resourceClass = String(this.window.resourceClass); var resourceName = String(this.window.resourceName); var moreOneDesktop = this.window.desktops.length !== 1; return (moreOneDesktop || this.window.onAllDesktops || this.window.modal || this.window.transient || !this.window.resizeable || (KWINCONFIG.floatUtility && (this.window.dialog || this.window.splash || this.window.utility)) || KWINCONFIG.floatingClass.indexOf(resourceClass) >= 0 || KWINCONFIG.floatingClass.indexOf(resourceName) >= 0 || matchWords(this.window.caption, KWINCONFIG.floatingTitle) >= 0); }, enumerable: false, configurable: true }); Object.defineProperty(KWinWindow.prototype, "surface", { get: function () { var activity; if (this.window.activities.length === 0) activity = this.workspace.currentActivity; else if (this.window.activities.indexOf(this.workspace.currentActivity) >= 0) activity = this.workspace.currentActivity; else activity = this.window.activities[0]; var desktop = this.window.desktops[0]; return new KWinSurface(this.window.output, activity, desktop, this.workspace); }, set: function (srf) { var ksrf = srf; if (this.window.desktops[0] !== ksrf.desktop) this.window.desktops = [ksrf.desktop]; if (this.window.activities[0] !== ksrf.activity) this.window.activities = [ksrf.activity]; }, enumerable: false, configurable: true }); KWinWindow.prototype.commit = function (geometry, noBorder, keepAbove) { debugObj(function () { return ["KWinWindow#commit", { geometry: geometry, noBorder: noBorder, keepAbove: keepAbove }]; }); if (this.window.move || this.window.resize) return; if (noBorder !== undefined) { if (!this.noBorderManaged && noBorder) this.noBorderOriginal = this.window.noBorder; else if (this.noBorderManaged && !this.window.noBorder) this.noBorderOriginal = false; if (noBorder) this.window.noBorder = true; else if (this.noBorderManaged) this.window.noBorder = this.noBorderOriginal; this.noBorderManaged = noBorder; } if (keepAbove !== undefined) this.window.keepAbove = keepAbove; if (geometry !== undefined) { geometry = this.adjustGeometry(geometry); if (KWINCONFIG.preventProtrusion) { var area = toRect(this.workspace.clientArea(0, this.window.output, this.workspace.currentDesktop)); if (!area.includes(geometry)) { var x = geometry.x + Math.min(area.maxX - geometry.maxX, 0); var y = geometry.y + Math.min(area.maxY - geometry.maxY, 0); geometry = new Rect(x, y, geometry.width, geometry.height); geometry = this.adjustGeometry(geometry); } } this.window.frameGeometry = toQRect(geometry); this.window.rect; } }; KWinWindow.prototype.toString = function () { return ("KWin(" + this.window.internalId.toString() + "." + this.window.resourceClass + ")"); }; KWinWindow.prototype.visible = function (srf) { var ksrf = srf; return (!this.window.minimized && (this.window.onAllDesktops || this.window.desktops.indexOf(ksrf.desktop) !== -1) && (this.window.activities.length === 0 || this.window.activities.indexOf(ksrf.activity) !== -1) && this.window.output === ksrf.output); }; KWinWindow.prototype.adjustGeometry = function (geometry) { var width = geometry.width; var height = geometry.height; if (!this.window.resizeable) { width = this.window.width; height = this.window.height; } else { width = clip(width, this.window.minSize.width, this.window.maxSize.width); height = clip(height, this.window.minSize.height, this.window.maxSize.height); } return new Rect(geometry.x, geometry.y, width, height); }; return KWinWindow; }()); function debugWin(win) { var w_props = [ { name: "caption", opt: win.caption }, { name: "output.name", opt: win.output.name }, { name: "resourceName", opt: win.resourceName }, { name: "resourceClass", opt: win.resourceClass }, { name: "desktopWindow", opt: win.desktopWindow }, { name: "windowRole", opt: win.windowRole }, { name: "windowType", opt: win.windowType }, { name: "pid", opt: win.pid }, { name: "internalId", opt: win.internalId }, { name: "stackingOrder", opt: win.stackingOrder }, { name: "size", opt: win.size }, { name: "width", opt: win.width }, { name: "height", opt: win.height }, { name: "dock", opt: win.dock }, { name: "toolbar", opt: win.toolbar }, { name: "menu", opt: win.menu }, { name: "dialog", opt: win.dialog }, { name: "splash", opt: win.splash }, { name: "utility", opt: win.utility }, { name: "dropdownMenu", opt: win.dropdownMenu }, { name: "popupMenu", opt: win.popupMenu }, { name: "tooltip", opt: win.tooltip }, { name: "notification", opt: win.notification }, { name: "criticalNotification", opt: win.criticalNotification }, { name: "appletPopup", opt: win.appletPopup }, { name: "onScreenDisplay", opt: win.onScreenDisplay }, { name: "comboBox", opt: win.comboBox }, { name: "managed", opt: win.managed }, { name: "popupWindow", opt: win.popupWindow }, { name: "outline", opt: win.outline }, { name: "fullScreenable", opt: win.fullScreenable }, { name: "closeable", opt: win.closeable }, { name: "minimizable", opt: win.minimizable }, { name: "specialWindow", opt: win.specialWindow }, { name: "modal", opt: win.modal }, { name: "resizeable", opt: win.resizeable }, { name: "minimized", opt: win.minimized }, { name: "tile", opt: win.tile }, { name: "minSize", opt: win.minSize }, { name: "maxSize", opt: win.maxSize }, { name: "transient", opt: win.transient }, { name: "transientFor", opt: win.transientFor }, { name: "maximizable", opt: win.maximizable }, { name: "moveable", opt: win.moveable }, { name: "moveableAcrossScreens", opt: win.moveableAcrossScreens }, { name: "hidden", opt: win.hidden }, { name: "keepAbove", opt: win.keepAbove }, { name: "keepBelow", opt: win.keepBelow }, { name: "opacity", opt: win.opacity }, ]; var s = "krohnkite:"; w_props.forEach(function (el) { if (typeof el.opt !== "undefined" && (el.opt || el.opt === 0 || el.opt === "0")) { s += "<"; s += el.name; s += ": "; s += el.opt; s += "> "; } }); return s; } var TestDriver = (function () { function TestDriver() { this.currentScreen = 0; this.currentWindow = 0; this.numScreen = 1; this.screenSize = new Rect(0, 0, 10000, 10000); this.windows = []; } TestDriver.prototype.forEachScreen = function (func) { for (var screen = 0; screen < this.numScreen; screen++) func(new TestSurface(this, screen)); }; TestDriver.prototype.getCurrentContext = function () { var window = this.getCurrentWindow(); if (window) return window.surface; return new TestSurface(this, 0); }; TestDriver.prototype.getCurrentWindow = function () { return this.windows.length !== 0 ? this.windows[this.currentWindow] : null; }; TestDriver.prototype.getWorkingArea = function (srf) { return this.screenSize; }; TestDriver.prototype.setCurrentWindow = function (window) { var idx = this.windows.indexOf(window); if (idx !== -1) this.currentWindow = idx; }; TestDriver.prototype.setTimeout = function (func, timeout) { setTimeout(func, timeout); }; return TestDriver; }()); var TestSurface = (function () { function TestSurface(driver, screen) { this.driver = driver; this.screen = screen; } Object.defineProperty(TestSurface.prototype, "id", { get: function () { return String(this.screen); }, enumerable: false, configurable: true }); Object.defineProperty(TestSurface.prototype, "ignore", { get: function () { return false; }, enumerable: false, configurable: true }); Object.defineProperty(TestSurface.prototype, "workingArea", { get: function () { return this.driver.screenSize; }, enumerable: false, configurable: true }); TestSurface.prototype.next = function () { return new TestSurface(this.driver, this.screen + 1); }; return TestSurface; }()); var TestWindow = (function () { function TestWindow(srf, geometry, ignore, float) { this.id = String(TestWindow.windowCount); TestWindow.windowCount += 1; this.shouldFloat = float !== undefined ? float : false; this.shouldIgnore = ignore !== undefined ? ignore : false; this.surface = srf; this.fullScreen = false; this.geometry = geometry || new Rect(0, 0, 100, 100); this.keepAbove = false; this.maximized = false; this.noBorder = false; } TestWindow.prototype.commit = function (geometry, noBorder, keepAbove) { if (geometry) this.geometry = geometry; if (noBorder !== undefined) this.noBorder = noBorder; if (keepAbove !== undefined) this.keepAbove = keepAbove; }; TestWindow.prototype.focus = function () { }; TestWindow.prototype.visible = function (srf) { var tctx = srf; return this.surface.screen === tctx.screen; }; TestWindow.windowCount = 0; return TestWindow; }()); function setTestConfig(name, value) { if (!CONFIG) CONFIG = {}; CONFIG[name] = value; } var TilingController = (function () { function TilingController(engine) { this.engine = engine; } TilingController.prototype.onSurfaceUpdate = function (ctx, comment) { debugObj(function () { return ["onSurfaceUpdate", { comment: comment }]; }); this.engine.arrange(ctx); }; TilingController.prototype.onCurrentActivityChanged = function (ctx, activityId) { debugObj(function () { return ["onCurrentActivityChanged", { activityId: activityId }]; }); this.engine.arrange(ctx); }; TilingController.prototype.onCurrentSurfaceChanged = function (ctx) { debugObj(function () { return ["onCurrentSurfaceChanged", { srf: ctx.currentSurface }]; }); this.engine.arrange(ctx); }; TilingController.prototype.onWindowAdded = function (ctx, window) { debugObj(function () { return ["onWindowAdded", { window: window }]; }); this.engine.manage(window); if (window.tileable) { var srf = ctx.currentSurface; var tiles = this.engine.windows.getVisibleTiles(srf); var layoutCapcity = this.engine.layouts.getCurrentLayout(srf).capacity; if (layoutCapcity !== undefined && tiles.length > layoutCapcity) { var nsrf = ctx.currentSurface.next(); if (nsrf) { window.surface = nsrf; ctx.currentSurface = nsrf; } } } this.engine.arrange(ctx); }; TilingController.prototype.onWindowRemoved = function (ctx, window) { debugObj(function () { return ["onWindowRemoved", { window: window }]; }); this.engine.unmanage(window); this.engine.arrange(ctx); }; TilingController.prototype.onWindowMoveStart = function (window) { }; TilingController.prototype.onWindowMove = function (window) { }; TilingController.prototype.onWindowMoveOver = function (ctx, window) { debugObj(function () { return ["onWindowMoveOver", { window: window }]; }); if (window.state === WindowState.Tiled) { var tiles = this.engine.windows.getVisibleTiles(ctx.currentSurface); var cursorPos_1 = ctx.cursorPosition || window.actualGeometry.center; var targets = tiles.filter(function (tile) { return tile !== window && tile.actualGeometry.includesPoint(cursorPos_1); }); if (targets.length === 1) { this.engine.windows.swap(window, targets[0]); this.engine.arrange(ctx); return; } } if (!CONFIG.keepTilingOnDrag && window.state === WindowState.Tiled) { var diff = window.actualGeometry.subtract(window.geometry); var distance = Math.sqrt(Math.pow(diff.x, 2) + Math.pow(diff.y, 2)); if (distance > 30) { window.floatGeometry = window.actualGeometry; window.state = WindowState.Floating; this.engine.arrange(ctx); return; } } window.commit(); }; TilingController.prototype.onWindowResizeStart = function (window) { }; TilingController.prototype.onWindowResize = function (ctx, window) { debugObj(function () { return ["onWindowResize", { window: window }]; }); if (CONFIG.adjustLayout && CONFIG.adjustLayoutLive) { if (window.state === WindowState.Tiled) { this.engine.adjustLayout(window); this.engine.arrange(ctx); } } }; TilingController.prototype.onWindowResizeOver = function (ctx, window) { debugObj(function () { return ["onWindowResizeOver", { window: window }]; }); if (CONFIG.adjustLayout && window.tiled) { this.engine.adjustLayout(window); this.engine.arrange(ctx); } else if (!CONFIG.adjustLayout) this.engine.enforceSize(ctx, window); }; TilingController.prototype.onWindowMaximizeChanged = function (ctx, window, maximized) { this.engine.arrange(ctx); }; TilingController.prototype.onWindowGeometryChanged = function (ctx, window) { debugObj(function () { return ["onWindowGeometryChanged", { window: window }]; }); this.engine.enforceSize(ctx, window); }; TilingController.prototype.onWindowChanged = function (ctx, window, comment) { if (window) { debugObj(function () { return ["onWindowChanged", { window: window, comment: comment }]; }); if (comment === "unminimized") ctx.currentWindow = window; this.engine.arrange(ctx); } }; TilingController.prototype.onWindowFocused = function (ctx, window) { window.timestamp = new Date().getTime(); }; TilingController.prototype.onShortcut = function (ctx, input, data) { if (CONFIG.directionalKeyMode === "dwm") { switch (input) { case Shortcut.FocusUp: input = Shortcut.FocusNext; break; case Shortcut.FocusDown: input = Shortcut.FocusPrev; break; case Shortcut.FocusLeft: input = Shortcut.DWMLeft; break; case Shortcut.FocusRight: input = Shortcut.DWMRight; break; } } else if (CONFIG.directionalKeyMode === "focus") { switch (input) { case Shortcut.ShiftUp: input = Shortcut.SwapUp; break; case Shortcut.ShiftDown: input = Shortcut.SwapDown; break; case Shortcut.ShiftLeft: input = Shortcut.SwapLeft; break; case Shortcut.ShiftRight: input = Shortcut.SwapRight; break; } } if (this.engine.handleLayoutShortcut(ctx, input, data)) { this.engine.arrange(ctx); return; } var window = ctx.currentWindow; switch (input) { case Shortcut.FocusNext: this.engine.focusOrder(ctx, -1); break; case Shortcut.FocusPrev: this.engine.focusOrder(ctx, +1); break; case Shortcut.FocusUp: this.engine.focusDir(ctx, "up"); break; case Shortcut.FocusDown: this.engine.focusDir(ctx, "down"); break; case Shortcut.DWMLeft: case Shortcut.FocusLeft: this.engine.focusDir(ctx, "left"); break; case Shortcut.DWMRight: case Shortcut.FocusRight: this.engine.focusDir(ctx, "right"); break; case Shortcut.GrowWidth: if (window) this.engine.resizeWindow(window, "east", 1); break; case Shortcut.ShrinkWidth: if (window) this.engine.resizeWindow(window, "east", -1); break; case Shortcut.GrowHeight: if (window) this.engine.resizeWindow(window, "south", 1); break; case Shortcut.ShrinkHeight: if (window) this.engine.resizeWindow(window, "south", -1); break; case Shortcut.ShiftUp: if (window) this.engine.swapOrder(window, -1); break; case Shortcut.ShiftDown: if (window) this.engine.swapOrder(window, +1); break; case Shortcut.SwapUp: this.engine.swapDirOrMoveFloat(ctx, "up"); break; case Shortcut.SwapDown: this.engine.swapDirOrMoveFloat(ctx, "down"); break; case Shortcut.SwapLeft: this.engine.swapDirOrMoveFloat(ctx, "left"); break; case Shortcut.SwapRight: this.engine.swapDirOrMoveFloat(ctx, "right"); break; case Shortcut.SetMaster: if (window) this.engine.setMaster(window); break; case Shortcut.ToggleFloat: if (window) this.engine.toggleFloat(window); break; case Shortcut.ToggleFloatAll: this.engine.floatAll(ctx, ctx.currentSurface); break; case Shortcut.NextLayout: this.engine.cycleLayout(ctx, 1); break; case Shortcut.PreviousLayout: this.engine.cycleLayout(ctx, -1); break; case Shortcut.SetLayout: if (typeof data === "string") this.engine.setLayout(ctx, data); break; } this.engine.arrange(ctx); }; return TilingController; }()); var TilingEngine = (function () { function TilingEngine() { this.layouts = new LayoutStore(); this.windows = new WindowStore(); } TilingEngine.prototype.adjustLayout = function (basis) { var srf = basis.surface; var layout = this.layouts.getCurrentLayout(srf); if (layout.adjust) { var area = srf.workingArea.gap(CONFIG.screenGapLeft, CONFIG.screenGapRight, CONFIG.screenGapTop, CONFIG.screenGapBottom); var tiles = this.windows.getVisibleTiles(srf); layout.adjust(area, tiles, basis, basis.geometryDelta); } }; TilingEngine.prototype.resizeFloat = function (window, dir, step) { var srf = window.surface; var hStepSize = srf.workingArea.width * 0.05; var vStepSize = srf.workingArea.height * 0.05; var hStep, vStep; switch (dir) { case "east": (hStep = step), (vStep = 0); break; case "west": (hStep = -step), (vStep = 0); break; case "south": (hStep = 0), (vStep = step); break; case "north": (hStep = 0), (vStep = -step); break; } var geometry = window.actualGeometry; var width = geometry.width + hStepSize * hStep; var height = geometry.height + vStepSize * vStep; window.forceSetGeometry(new Rect(geometry.x, geometry.y, width, height)); }; TilingEngine.prototype.resizeTile = function (basis, dir, step) { var srf = basis.surface; if (dir === "east") { var maxX_1 = basis.geometry.maxX; var easternNeighbor = this.windows .getVisibleTiles(srf) .filter(function (tile) { return tile.geometry.x >= maxX_1; }); if (easternNeighbor.length === 0) { dir = "west"; step *= -1; } } else if (dir === "south") { var maxY_1 = basis.geometry.maxY; var southernNeighbor = this.windows .getVisibleTiles(srf) .filter(function (tile) { return tile.geometry.y >= maxY_1; }); if (southernNeighbor.length === 0) { dir = "north"; step *= -1; } } var hStepSize = srf.workingArea.width * 0.03; var vStepSize = srf.workingArea.height * 0.03; var delta; switch (dir) { case "east": delta = new RectDelta(hStepSize * step, 0, 0, 0); break; case "west": delta = new RectDelta(0, hStepSize * step, 0, 0); break; case "south": delta = new RectDelta(0, 0, vStepSize * step, 0); break; case "north": default: delta = new RectDelta(0, 0, 0, vStepSize * step); break; } var layout = this.layouts.getCurrentLayout(srf); if (layout.adjust) { var area = srf.workingArea.gap(CONFIG.screenGapLeft, CONFIG.screenGapRight, CONFIG.screenGapTop, CONFIG.screenGapBottom); layout.adjust(area, this.windows.getVisibleTileables(srf), basis, delta); } }; TilingEngine.prototype.resizeWindow = function (window, dir, step) { var state = window.state; if (WindowClass.isFloatingState(state)) this.resizeFloat(window, dir, step); else if (WindowClass.isTiledState(state)) this.resizeTile(window, dir, step); }; TilingEngine.prototype.arrange = function (ctx) { var _this = this; debug(function () { return "arrange"; }); ctx.screens.forEach(function (srf) { _this.arrangeScreen(ctx, srf); }); }; TilingEngine.prototype.arrangeScreen = function (ctx, srf) { var layout = this.layouts.getCurrentLayout(srf); var workingArea = srf.workingArea; var tilingArea; if (CONFIG.monocleMaximize && layout instanceof MonocleLayout) tilingArea = workingArea; else tilingArea = workingArea.gap(CONFIG.screenGapLeft, CONFIG.screenGapRight, CONFIG.screenGapTop, CONFIG.screenGapBottom); var visibles = this.windows.getVisibleWindows(srf); debugObj(function () { return [ "arrangeScreen", { layout: layout, srf: srf, visibles: visibles.length, }, ]; }); visibles.forEach(function (window) { if (window.state === WindowState.Undecided) window.state = window.shouldFloat ? WindowState.Floating : WindowState.Tiled; }); var tileables = this.windows.getVisibleTileables(srf); if (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)) { var maxWidth_1 = Math.floor(workingArea.height * CONFIG.limitTileWidthRatio); tileables .filter(function (tile) { return tile.tiled && tile.geometry.width > maxWidth_1; }) .forEach(function (tile) { var g = tile.geometry; tile.geometry = new Rect(g.x + Math.floor((g.width - maxWidth_1) / 2), g.y, maxWidth_1, g.height); }); } visibles.forEach(function (window) { return window.commit(); }); debugObj(function () { return ["arrangeScreen/finished", { srf: srf }]; }); }; TilingEngine.prototype.enforceSize = function (ctx, window) { if (window.tiled && !window.actualGeometry.equals(window.geometry)) ctx.setTimeout(function () { if (window.tiled) window.commit(); }, 10); }; TilingEngine.prototype.manage = function (window) { if (!window.shouldIgnore) { window.state = WindowState.Undecided; if (CONFIG.newWindowPosition === 1) this.windows.unshift(window); else if (CONFIG.newWindowPosition === 2) { this.windows.beside_first(window); } else this.windows.push(window); } }; TilingEngine.prototype.unmanage = function (window) { this.windows.remove(window); }; TilingEngine.prototype.focusOrder = function (ctx, step) { var window = ctx.currentWindow; if (window === null) { var tiles = this.windows.getVisibleTiles(ctx.currentSurface); if (tiles.length > 1) ctx.currentWindow = tiles[0]; return; } var visibles = this.windows.getVisibleWindows(ctx.currentSurface); if (visibles.length === 0) return; var idx = visibles.indexOf(window); if (!window || idx < 0) { ctx.currentWindow = visibles[0]; return; } var num = visibles.length; var newIndex = (idx + (step % num) + num) % num; ctx.currentWindow = visibles[newIndex]; }; TilingEngine.prototype.focusDir = function (ctx, dir) { var window = ctx.currentWindow; if (window === null) { var tiles = this.windows.getVisibleTiles(ctx.currentSurface); if (tiles.length > 1) ctx.currentWindow = tiles[0]; return; } var neighbor = this.getNeighborByDirection(ctx, window, dir); if (neighbor) ctx.currentWindow = neighbor; }; TilingEngine.prototype.swapOrder = function (window, step) { var srf = window.surface; var visibles = this.windows.getVisibleWindows(srf); if (visibles.length < 2) return; var vsrc = visibles.indexOf(window); var vdst = wrapIndex(vsrc + step, visibles.length); var dstWin = visibles[vdst]; this.windows.move(window, dstWin); }; TilingEngine.prototype.swapDirection = function (ctx, dir) { var window = ctx.currentWindow; if (window === null) { var tiles = this.windows.getVisibleTiles(ctx.currentSurface); if (tiles.length > 1) ctx.currentWindow = tiles[0]; return; } var neighbor = this.getNeighborByDirection(ctx, window, dir); if (neighbor) this.windows.swap(window, neighbor); }; TilingEngine.prototype.moveFloat = function (window, dir) { var srf = window.surface; var hStepSize = srf.workingArea.width * 0.05; var vStepSize = srf.workingArea.height * 0.05; var hStep, vStep; switch (dir) { case "up": (hStep = 0), (vStep = -1); break; case "down": (hStep = 0), (vStep = 1); break; case "left": (hStep = -1), (vStep = 0); break; case "right": (hStep = 1), (vStep = 0); break; } var geometry = window.actualGeometry; var x = geometry.x + hStepSize * hStep; var y = geometry.y + vStepSize * vStep; window.forceSetGeometry(new Rect(x, y, geometry.width, geometry.height)); }; TilingEngine.prototype.swapDirOrMoveFloat = function (ctx, dir) { var window = ctx.currentWindow; if (!window) return; var state = window.state; if (WindowClass.isFloatingState(state)) this.moveFloat(window, dir); else if (WindowClass.isTiledState(state)) this.swapDirection(ctx, dir); }; TilingEngine.prototype.toggleFloat = function (window) { window.state = !window.tileable ? WindowState.Tiled : WindowState.Floating; }; TilingEngine.prototype.floatAll = function (ctx, srf) { var windows = this.windows.getVisibleWindows(srf); var numFloats = windows.reduce(function (count, window) { return window.state === WindowState.Floating ? count + 1 : count; }, 0); if (numFloats < windows.length / 2) { windows.forEach(function (window) { window.floatGeometry = window.actualGeometry.gap(4, 4, 4, 4); window.state = WindowState.Floating; }); ctx.showNotification("Float All"); } else { windows.forEach(function (window) { window.state = WindowState.Tiled; }); ctx.showNotification("Tile All"); } }; TilingEngine.prototype.setMaster = function (window) { this.windows.setMaster(window); }; TilingEngine.prototype.cycleLayout = function (ctx, step) { var layout = this.layouts.cycleLayout(ctx.currentSurface, step); if (layout) ctx.showNotification(layout.description); }; TilingEngine.prototype.setLayout = function (ctx, layoutClassID) { var layout = this.layouts.setLayout(ctx.currentSurface, layoutClassID); if (layout) ctx.showNotification(layout.description); }; TilingEngine.prototype.handleLayoutShortcut = function (ctx, input, data) { var layout = this.layouts.getCurrentLayout(ctx.currentSurface); if (layout.handleShortcut) return layout.handleShortcut(new EngineContext(ctx, this), input, data); return false; }; TilingEngine.prototype.getNeighborByDirection = function (ctx, basis, dir) { var vertical; var sign; switch (dir) { case "up": vertical = true; sign = -1; break; case "down": vertical = true; sign = 1; break; case "left": vertical = false; sign = -1; break; case "right": vertical = false; sign = 1; break; default: return null; } var candidates = this.windows .getVisibleTiles(ctx.currentSurface) .filter(vertical ? function (tile) { return tile.geometry.y * sign > basis.geometry.y * sign; } : function (tile) { return tile.geometry.x * sign > basis.geometry.x * sign; }) .filter(vertical ? function (tile) { return overlap(basis.geometry.x, basis.geometry.maxX, tile.geometry.x, tile.geometry.maxX); } : function (tile) { return overlap(basis.geometry.y, basis.geometry.maxY, tile.geometry.y, tile.geometry.maxY); }); if (candidates.length === 0) return null; var min = sign * candidates.reduce(vertical ? function (prevMin, tile) { return Math.min(tile.geometry.y * sign, prevMin); } : function (prevMin, tile) { return Math.min(tile.geometry.x * sign, prevMin); }, Infinity); var closest = candidates.filter(vertical ? function (tile) { return tile.geometry.y === min; } : function (tile) { return tile.geometry.x === min; }); return closest.sort(function (a, b) { return b.timestamp - a.timestamp; })[0]; }; return TilingEngine; }()); var EngineContext = (function () { function EngineContext(drvctx, engine) { this.drvctx = drvctx; this.engine = engine; } Object.defineProperty(EngineContext.prototype, "backend", { get: function () { return this.drvctx.backend; }, enumerable: false, configurable: true }); Object.defineProperty(EngineContext.prototype, "currentWindow", { get: function () { return this.drvctx.currentWindow; }, set: function (window) { this.drvctx.currentWindow = window; }, enumerable: false, configurable: true }); EngineContext.prototype.setTimeout = function (func, timeout) { this.drvctx.setTimeout(func, timeout); }; EngineContext.prototype.cycleFocus = function (step) { this.engine.focusOrder(this.drvctx, step); }; EngineContext.prototype.moveWindow = function (window, target, after) { this.engine.windows.move(window, target, after); }; EngineContext.prototype.showNotification = function (text) { this.drvctx.showNotification(text); }; return EngineContext; }()); var LayoutStoreEntry = (function () { function LayoutStoreEntry(output_name, desktop_name) { var _this = this; var layouts_str = CONFIG.layoutOrder.map(function (layout, i) { return i + "." + layout + ", "; }); print("Krohnkite: Screen(output):".concat(output_name, ", Desktop(name):").concat(desktop_name, ", layouts: ").concat(layouts_str)); this.currentIndex = 0; this.currentID = CONFIG.layoutOrder[0]; CONFIG.screenDefaultLayout.some(function (entry) { var cfg = entry.split(":"); var cfg_output = cfg[0]; var cfg_desktop = cfg.length == 2 ? undefined : cfg[1]; var cfg_screen_id_str = cfg.length == 2 ? cfg[1] : cfg[2]; var cfg_screen_id = parseInt(cfg_screen_id_str); if ((output_name === cfg_output || cfg_output === '') && (desktop_name === cfg_desktop || cfg_desktop === undefined) && cfg_screen_id >= 0 && cfg_screen_id < CONFIG.layoutOrder.length) { _this.currentIndex = cfg_screen_id; _this.currentID = CONFIG.layoutOrder[_this.currentIndex]; return true; } }); this.layouts = {}; this.previousID = this.currentID; this.loadLayout(this.currentID); } Object.defineProperty(LayoutStoreEntry.prototype, "currentLayout", { get: function () { return this.loadLayout(this.currentID); }, enumerable: false, configurable: true }); LayoutStoreEntry.prototype.cycleLayout = function (step) { this.previousID = this.currentID; this.currentIndex = this.currentIndex !== null ? wrapIndex(this.currentIndex + step, CONFIG.layoutOrder.length) : 0; this.currentID = CONFIG.layoutOrder[this.currentIndex]; return this.loadLayout(this.currentID); }; LayoutStoreEntry.prototype.setLayout = function (targetID) { var targetLayout = this.loadLayout(targetID); if (targetLayout instanceof MonocleLayout && this.currentLayout instanceof MonocleLayout) { this.currentID = this.previousID; this.previousID = targetID; } else if (this.currentID !== targetID) { this.previousID = this.currentID; this.currentID = targetID; } this.updateCurrentIndex(); return targetLayout; }; LayoutStoreEntry.prototype.updateCurrentIndex = function () { var idx = CONFIG.layoutOrder.indexOf(this.currentID); this.currentIndex = idx === -1 ? null : idx; }; LayoutStoreEntry.prototype.loadLayout = function (ID) { var layout = this.layouts[ID]; if (!layout) layout = this.layouts[ID] = CONFIG.layoutFactories[ID](); return layout; }; return LayoutStoreEntry; }()); var LayoutStore = (function () { function LayoutStore() { this.store = {}; } LayoutStore.prototype.getCurrentLayout = function (srf) { return srf.ignore ? FloatingLayout.instance : this.getEntry(srf.id).currentLayout; }; LayoutStore.prototype.cycleLayout = function (srf, step) { if (srf.ignore) return null; return this.getEntry(srf.id).cycleLayout(step); }; LayoutStore.prototype.setLayout = function (srf, layoutClassID) { if (srf.ignore) return null; return this.getEntry(srf.id).setLayout(layoutClassID); }; LayoutStore.prototype.getEntry = function (key) { if (!this.store[key]) { var i1 = key.indexOf("@"); var i2 = key.indexOf("#"); var key_without_activity = key.slice(0, i1 + 1) + key.slice(i2); if (i1 > 0 && i2 > 0 && i2 - i1 > 1 && this.store[key_without_activity]) { this.store[key] = this.store[key_without_activity]; delete this.store[key_without_activity]; } else { var output_name = key.slice(0, key.indexOf("@")); var desktop_name = i2 !== -1 ? key.slice(i2 + 1) : undefined; this.store[key] = new LayoutStoreEntry(output_name, desktop_name); } } return this.store[key]; }; return LayoutStore; }()); var WindowState; (function (WindowState) { WindowState[WindowState["Unmanaged"] = 0] = "Unmanaged"; WindowState[WindowState["NativeFullscreen"] = 1] = "NativeFullscreen"; WindowState[WindowState["NativeMaximized"] = 2] = "NativeMaximized"; WindowState[WindowState["Floating"] = 3] = "Floating"; WindowState[WindowState["Maximized"] = 4] = "Maximized"; WindowState[WindowState["Tiled"] = 5] = "Tiled"; WindowState[WindowState["TiledAfloat"] = 6] = "TiledAfloat"; WindowState[WindowState["Undecided"] = 7] = "Undecided"; })(WindowState || (WindowState = {})); var WindowClass = (function () { function WindowClass(window) { this.id = window.id; this.window = window; this.floatGeometry = window.geometry; this.geometry = window.geometry; this.timestamp = 0; this.internalState = WindowState.Unmanaged; this.shouldCommitFloat = this.shouldFloat; this.weightMap = {}; } WindowClass.isTileableState = function (state) { return (state === WindowState.Tiled || state === WindowState.Maximized || state === WindowState.TiledAfloat); }; WindowClass.isTiledState = function (state) { return state === WindowState.Tiled || state === WindowState.Maximized; }; WindowClass.isFloatingState = function (state) { return state === WindowState.Floating || state === WindowState.TiledAfloat; }; Object.defineProperty(WindowClass.prototype, "actualGeometry", { get: function () { return this.window.geometry; }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "shouldFloat", { get: function () { return this.window.shouldFloat; }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "shouldIgnore", { get: function () { return this.window.shouldIgnore; }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "tileable", { get: function () { return WindowClass.isTileableState(this.state); }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "tiled", { get: function () { return WindowClass.isTiledState(this.state); }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "floating", { get: function () { return WindowClass.isFloatingState(this.state); }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "geometryDelta", { get: function () { return RectDelta.fromRects(this.geometry, this.actualGeometry); }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "state", { get: function () { if (this.window.fullScreen) return WindowState.NativeFullscreen; if (this.window.maximized) return WindowState.NativeMaximized; return this.internalState; }, set: function (value) { var state = this.state; if (state === value) return; if ((state === WindowState.Unmanaged || WindowClass.isTileableState(state)) && WindowClass.isFloatingState(value)) this.shouldCommitFloat = true; else if (WindowClass.isFloatingState(state) && WindowClass.isTileableState(value)) this.floatGeometry = this.actualGeometry; this.internalState = value; }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "surface", { get: function () { return this.window.surface; }, set: function (srf) { this.window.surface = srf; }, enumerable: false, configurable: true }); Object.defineProperty(WindowClass.prototype, "weight", { get: function () { var srfID = this.window.surface.id; var weight = this.weightMap[srfID]; if (weight === undefined) { this.weightMap[srfID] = 1.0; return 1.0; } return weight; }, set: function (value) { var srfID = this.window.surface.id; this.weightMap[srfID] = value; }, enumerable: false, configurable: true }); WindowClass.prototype.commit = function () { var state = this.state; debugObj(function () { return ["Window#commit", { state: WindowState[state] }]; }); switch (state) { case WindowState.NativeMaximized: this.window.commit(undefined, undefined, false); break; case WindowState.NativeFullscreen: this.window.commit(undefined, undefined, undefined); break; case WindowState.Floating: if (!this.shouldCommitFloat) break; this.window.commit(this.floatGeometry, false, CONFIG.keepFloatAbove); this.shouldCommitFloat = false; break; case WindowState.Maximized: this.window.commit(this.geometry, true, false); break; case WindowState.Tiled: this.window.commit(this.geometry, CONFIG.noTileBorder, false); break; case WindowState.TiledAfloat: if (!this.shouldCommitFloat) break; this.window.commit(this.floatGeometry, false, CONFIG.keepFloatAbove); this.shouldCommitFloat = false; break; } }; WindowClass.prototype.forceSetGeometry = function (geometry) { this.window.commit(geometry); }; WindowClass.prototype.visible = function (srf) { return this.window.visible(srf); }; WindowClass.prototype.toString = function () { return "Window(" + String(this.window) + ")"; }; return WindowClass; }()); var WindowStore = (function () { function WindowStore(windows) { this.list = windows || []; } WindowStore.prototype.move = function (srcWin, destWin, after) { var srcIdx = this.list.indexOf(srcWin); var destIdx = this.list.indexOf(destWin); if (srcIdx === -1 || destIdx === -1) return; this.list.splice(srcIdx, 1); this.list.splice(after ? destIdx + 1 : destIdx, 0, srcWin); }; WindowStore.prototype.setMaster = function (window) { var idx = this.list.indexOf(window); if (idx === -1) return; this.list.splice(idx, 1); this.list.splice(0, 0, window); }; WindowStore.prototype.swap = function (alpha, beta) { var alphaIndex = this.list.indexOf(alpha); var betaIndex = this.list.indexOf(beta); if (alphaIndex < 0 || betaIndex < 0) return; this.list[alphaIndex] = beta; this.list[betaIndex] = alpha; }; Object.defineProperty(WindowStore.prototype, "length", { get: function () { return this.list.length; }, enumerable: false, configurable: true }); WindowStore.prototype.at = function (idx) { return this.list[idx]; }; WindowStore.prototype.indexOf = function (window) { return this.list.indexOf(window); }; WindowStore.prototype.push = function (window) { this.list.push(window); }; WindowStore.prototype.beside_first = function (window) { this.list.splice(1, 0, window); }; WindowStore.prototype.remove = function (window) { var idx = this.list.indexOf(window); if (idx >= 0) this.list.splice(idx, 1); }; WindowStore.prototype.unshift = function (window) { this.list.unshift(window); }; WindowStore.prototype.getVisibleWindows = function (srf) { return this.list.filter(function (win) { return win.visible(srf); }); }; WindowStore.prototype.getVisibleTiles = function (srf) { return this.list.filter(function (win) { return win.tiled && win.visible(srf); }); }; WindowStore.prototype.getVisibleTileables = function (srf) { return this.list.filter(function (win) { return win.tileable && win.visible(srf); }); }; return WindowStore; }()); var BTreeLayout = (function () { function BTreeLayout() { this.classID = BTreeLayout.id; this.parts = new HalfSplitLayoutPart(new FillLayoutPart(), new FillLayoutPart()); this.parts.angle = 0; this.parts.gap = CONFIG.tileLayoutGap; } Object.defineProperty(BTreeLayout.prototype, "description", { get: function () { return "BTree"; }, enumerable: false, configurable: true }); BTreeLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); this.create_parts(tileables.length); var rectangles = this.parts.apply(area, tileables); rectangles.forEach(function (geometry, i) { tileables[i].geometry = geometry; }); }; BTreeLayout.prototype.create_parts = function (tiles_len) { var head = this.get_head(); head.angle = 0; head.gap = CONFIG.tileLayoutGap; if (tiles_len > 2) { var level = Math.ceil(Math.log(tiles_len) * 1.442695); var level_capacity = Math.pow(2, (level - 1)); var half_level_capacity = Math.pow(2, (level - 2)); if (tiles_len > level_capacity + half_level_capacity) { head.primarySize = tiles_len - level_capacity; } else { head.primarySize = half_level_capacity; } this.build_binary_tree(head, level, 2, tiles_len); } this.parts = head; }; BTreeLayout.prototype.build_binary_tree = function (head, max_level, current_level, tiles_len) { if (current_level <= max_level) { if (head.primarySize > 1) { var primary = this.get_head(); primary.primarySize = Math.floor(head.primarySize / 2); primary.gap = CONFIG.tileLayoutGap; primary.angle = current_level % 2 ? 0 : 90; head.primary = primary; this.build_binary_tree(primary, max_level, current_level + 1, head.primarySize); } if (tiles_len - head.primarySize > 1) { var secondary = this.get_head(); secondary.primarySize = Math.floor((tiles_len - head.primarySize) / 2); secondary.gap = CONFIG.tileLayoutGap; secondary.angle = current_level % 2 ? 0 : 90; head.secondary = secondary; this.build_binary_tree(secondary, max_level, current_level + 1, tiles_len - head.primarySize); } } }; BTreeLayout.prototype.get_head = function () { return new HalfSplitLayoutPart(new FillLayoutPart(), new FillLayoutPart()); }; BTreeLayout.prototype.clone = function () { var other = new StackedLayout(); return other; }; BTreeLayout.prototype.toString = function () { return "BTreeLayout()"; }; BTreeLayout.id = "BTreeLayout"; return BTreeLayout; }()); var CascadeDirection; (function (CascadeDirection) { CascadeDirection[CascadeDirection["NorthWest"] = 0] = "NorthWest"; CascadeDirection[CascadeDirection["North"] = 1] = "North"; CascadeDirection[CascadeDirection["NorthEast"] = 2] = "NorthEast"; CascadeDirection[CascadeDirection["East"] = 3] = "East"; CascadeDirection[CascadeDirection["SouthEast"] = 4] = "SouthEast"; CascadeDirection[CascadeDirection["South"] = 5] = "South"; CascadeDirection[CascadeDirection["SouthWest"] = 6] = "SouthWest"; CascadeDirection[CascadeDirection["West"] = 7] = "West"; })(CascadeDirection || (CascadeDirection = {})); var CascadeLayout = (function () { function CascadeLayout(dir) { if (dir === void 0) { dir = CascadeDirection.SouthEast; } this.dir = dir; this.classID = CascadeLayout.id; } CascadeLayout.decomposeDirection = function (dir) { switch (dir) { case CascadeDirection.NorthWest: return [-1, -1]; case CascadeDirection.North: return [-1, 0]; case CascadeDirection.NorthEast: return [-1, 1]; case CascadeDirection.East: return [0, 1]; case CascadeDirection.SouthEast: return [1, 1]; case CascadeDirection.South: return [1, 0]; case CascadeDirection.SouthWest: return [1, -1]; case CascadeDirection.West: return [0, -1]; } }; Object.defineProperty(CascadeLayout.prototype, "description", { get: function () { return "Cascade [" + CascadeDirection[this.dir] + "]"; }, enumerable: false, configurable: true }); CascadeLayout.prototype.apply = function (ctx, tileables, area) { var _a = CascadeLayout.decomposeDirection(this.dir), vertStep = _a[0], horzStep = _a[1]; var stepSize = 25; var windowWidth = horzStep !== 0 ? area.width - stepSize * (tileables.length - 1) : area.width; var windowHeight = vertStep !== 0 ? area.height - stepSize * (tileables.length - 1) : area.height; var baseX = horzStep >= 0 ? area.x : area.maxX - windowWidth; var baseY = vertStep >= 0 ? area.y : area.maxY - windowHeight; var x = baseX, y = baseY; tileables.forEach(function (tile) { tile.state = WindowState.Tiled; tile.geometry = new Rect(x, y, windowWidth, windowHeight); x += horzStep * stepSize; y += vertStep * stepSize; }); }; CascadeLayout.prototype.clone = function () { return new CascadeLayout(this.dir); }; CascadeLayout.prototype.handleShortcut = function (ctx, input, data) { switch (input) { case Shortcut.Increase: this.dir = (this.dir + 1 + 8) % 8; ctx.showNotification(this.description); break; case Shortcut.Decrease: this.dir = (this.dir - 1 + 8) % 8; ctx.showNotification(this.description); break; default: return false; } return true; }; CascadeLayout.id = "CascadeLayout"; return CascadeLayout; }()); var FloatingLayout = (function () { function FloatingLayout() { this.classID = FloatingLayout.id; this.description = "Floating"; } FloatingLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.TiledAfloat); }); }; FloatingLayout.prototype.clone = function () { return this; }; FloatingLayout.prototype.toString = function () { return "FloatingLayout()"; }; FloatingLayout.id = "FloatingLayout "; FloatingLayout.instance = new FloatingLayout(); return FloatingLayout; }()); var FillLayoutPart = (function () { function FillLayoutPart() { } FillLayoutPart.prototype.adjust = function (area, tiles, basis, delta) { return delta; }; FillLayoutPart.prototype.apply = function (area, tiles) { return tiles.map(function (tile) { return area; }); }; FillLayoutPart.prototype.toString = function () { return "FillLayoutPart"; }; return FillLayoutPart; }()); var HalfSplitLayoutPart = (function () { function HalfSplitLayoutPart(primary, secondary) { this.primary = primary; this.secondary = secondary; this.angle = 0; this.gap = 0; this.primarySize = 1; this.ratio = 0.5; } Object.defineProperty(HalfSplitLayoutPart.prototype, "horizontal", { get: function () { return this.angle === 0 || this.angle === 180; }, enumerable: false, configurable: true }); Object.defineProperty(HalfSplitLayoutPart.prototype, "reversed", { get: function () { return this.angle === 180 || this.angle === 270; }, enumerable: false, configurable: true }); HalfSplitLayoutPart.prototype.adjust = function (area, tiles, basis, delta) { var basisIndex = tiles.indexOf(basis); if (basisIndex < 0) return delta; if (tiles.length <= this.primarySize) { return this.primary.adjust(area, tiles, basis, delta); } else if (this.primarySize === 0) { return this.secondary.adjust(area, tiles, basis, delta); } else { var targetIndex = basisIndex < this.primarySize ? 0 : 1; if (targetIndex === 0) { delta = this.primary.adjust(area, tiles.slice(0, this.primarySize), basis, delta); } else { delta = this.secondary.adjust(area, tiles.slice(this.primarySize), basis, delta); } this.ratio = LayoutUtils.adjustAreaHalfWeights(area, this.reversed ? 1 - this.ratio : this.ratio, this.gap, this.reversed ? 1 - targetIndex : targetIndex, delta, this.horizontal); if (this.reversed) this.ratio = 1 - this.ratio; switch (this.angle * 10 + targetIndex + 1) { case 1: case 1802: return new RectDelta(0, delta.west, delta.south, delta.north); case 2: case 1801: return new RectDelta(delta.east, 0, delta.south, delta.north); case 901: case 2702: return new RectDelta(delta.east, delta.west, 0, delta.north); case 902: case 2701: return new RectDelta(delta.east, delta.west, delta.south, 0); } return delta; } }; HalfSplitLayoutPart.prototype.toString = function () { return ">>"); }; HalfSplitLayoutPart.prototype.apply = function (area, tiles) { if (tiles.length <= this.primarySize) { return this.primary.apply(area, tiles); } else if (this.primarySize === 0) { return this.secondary.apply(area, tiles); } else { var reversed = this.reversed; var ratio = reversed ? 1 - this.ratio : this.ratio; var _a = LayoutUtils.splitAreaHalfWeighted(area, ratio, this.gap, this.horizontal), area1 = _a[0], area2 = _a[1]; var result1 = this.primary.apply(reversed ? area2 : area1, tiles.slice(0, this.primarySize)); var result2 = this.secondary.apply(reversed ? area1 : area2, tiles.slice(this.primarySize)); return result1.concat(result2); } }; return HalfSplitLayoutPart; }()); var StackLayoutPart = (function () { function StackLayoutPart() { this.gap = 0; } StackLayoutPart.prototype.adjust = function (area, tiles, basis, delta) { var weights = LayoutUtils.adjustAreaWeights(area, tiles.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap, tiles.indexOf(basis), delta, false); weights.forEach(function (weight, i) { tiles[i].weight = weight * tiles.length; }); var idx = tiles.indexOf(basis); return new RectDelta(delta.east, delta.west, idx === tiles.length - 1 ? delta.south : 0, idx === 0 ? delta.north : 0); }; StackLayoutPart.prototype.apply = function (area, tiles) { var weights = tiles.map(function (tile) { return tile.weight; }); return LayoutUtils.splitAreaWeighted(area, weights, this.gap); }; return StackLayoutPart; }()); var RotateLayoutPart = (function () { function RotateLayoutPart(inner, angle) { if (angle === void 0) { angle = 0; } this.inner = inner; this.angle = angle; } RotateLayoutPart.prototype.adjust = function (area, tiles, basis, delta) { switch (this.angle) { case 0: break; case 90: area = new Rect(area.y, area.x, area.height, area.width); delta = new RectDelta(delta.south, delta.north, delta.east, delta.west); break; case 180: delta = new RectDelta(delta.west, delta.east, delta.south, delta.north); break; case 270: area = new Rect(area.y, area.x, area.height, area.width); delta = new RectDelta(delta.north, delta.south, delta.east, delta.west); break; } delta = this.inner.adjust(area, tiles, basis, delta); switch (this.angle) { case 0: delta = delta; break; case 90: delta = new RectDelta(delta.south, delta.north, delta.east, delta.west); break; case 180: delta = new RectDelta(delta.west, delta.east, delta.south, delta.north); break; case 270: delta = new RectDelta(delta.north, delta.south, delta.east, delta.west); break; } return delta; }; RotateLayoutPart.prototype.apply = function (area, tiles) { switch (this.angle) { case 0: break; case 90: area = new Rect(area.y, area.x, area.height, area.width); break; case 180: break; case 270: area = new Rect(area.y, area.x, area.height, area.width); break; } var innerResult = this.inner.apply(area, tiles); switch (this.angle) { case 0: return innerResult; case 90: return innerResult.map(function (g) { return new Rect(g.y, g.x, g.height, g.width); }); case 180: return innerResult.map(function (g) { var rx = g.x - area.x; var newX = area.x + area.width - (rx + g.width); return new Rect(newX, g.y, g.width, g.height); }); case 270: return innerResult.map(function (g) { var rx = g.x - area.x; var newY = area.x + area.width - (rx + g.width); return new Rect(g.y, newY, g.height, g.width); }); } }; RotateLayoutPart.prototype.rotate = function (amount) { var angle = this.angle + amount; if (angle < 0) angle = 270; else if (angle >= 360) angle = 0; this.angle = angle; }; return RotateLayoutPart; }()); var LayoutUtils = (function () { function LayoutUtils() { } LayoutUtils.splitWeighted = function (_a, weights, gap) { var begin = _a[0], length = _a[1]; gap = gap !== undefined ? gap : 0; var n = weights.length; var actualLength = length - (n - 1) * gap; var weightSum = weights.reduce(function (sum, weight) { return sum + weight; }, 0); var weightAcc = 0; return weights.map(function (weight, i) { var partBegin = (actualLength * weightAcc) / weightSum + i * gap; var partLength = (actualLength * weight) / weightSum; weightAcc += weight; return [begin + Math.floor(partBegin), Math.floor(partLength)]; }); }; LayoutUtils.splitAreaWeighted = function (area, weights, gap, horizontal) { gap = gap !== undefined ? gap : 0; horizontal = horizontal !== undefined ? horizontal : false; var line = horizontal ? [area.x, area.width] : [area.y, area.height]; var parts = LayoutUtils.splitWeighted(line, weights, gap); return parts.map(function (_a) { var begin = _a[0], length = _a[1]; return horizontal ? new Rect(begin, area.y, length, area.height) : new Rect(area.x, begin, area.width, length); }); }; LayoutUtils.splitAreaHalfWeighted = function (area, weight, gap, horizontal) { return LayoutUtils.splitAreaWeighted(area, [weight, 1 - weight], gap, horizontal); }; LayoutUtils.adjustWeights = function (_a, weights, gap, target, deltaFw, deltaBw) { var begin = _a[0], length = _a[1]; var minLength = 1; var parts = this.splitWeighted([begin, length], weights, gap); var _b = parts[target], targetBase = _b[0], targetLength = _b[1]; if (target > 0 && deltaBw !== 0) { var neighbor = target - 1; var _c = parts[neighbor], neighborBase = _c[0], neighborLength = _c[1]; var delta = clip(deltaBw, minLength - targetLength, neighborLength - minLength); parts[target] = [targetBase - delta, targetLength + delta]; parts[neighbor] = [neighborBase, neighborLength - delta]; } if (target < parts.length - 1 && deltaFw !== 0) { var neighbor = target + 1; var _d = parts[neighbor], neighborBase = _d[0], neighborLength = _d[1]; var delta = clip(deltaFw, minLength - targetLength, neighborLength - minLength); parts[target] = [targetBase, targetLength + delta]; parts[neighbor] = [neighborBase + delta, neighborLength - delta]; } return LayoutUtils.calculateWeights(parts); }; LayoutUtils.adjustAreaWeights = function (area, weights, gap, target, delta, horizontal) { var line = horizontal ? [area.x, area.width] : [area.y, area.height]; var _a = horizontal ? [delta.east, delta.west] : [delta.south, delta.north], deltaFw = _a[0], deltaBw = _a[1]; return LayoutUtils.adjustWeights(line, weights, gap, target, deltaFw, deltaBw); }; LayoutUtils.adjustAreaHalfWeights = function (area, weight, gap, target, delta, horizontal) { var weights = [weight, 1 - weight]; var newWeights = LayoutUtils.adjustAreaWeights(area, weights, gap, target, delta, horizontal); return newWeights[0]; }; LayoutUtils.calculateWeights = function (parts) { var totalLength = parts.reduce(function (acc, _a) { var base = _a[0], length = _a[1]; return acc + length; }, 0); return parts.map(function (_a) { var base = _a[0], length = _a[1]; return length / totalLength; }); }; LayoutUtils.calculateAreaWeights = function (area, geometries, gap, horizontal) { gap = gap !== undefined ? gap : 0; horizontal = horizontal !== undefined ? horizontal : false; var line = horizontal ? area.width : area.height; var parts = horizontal ? geometries.map(function (geometry) { return [geometry.x, geometry.width]; }) : geometries.map(function (geometry) { return [geometry.y, geometry.height]; }); return LayoutUtils.calculateWeights(parts); }; return LayoutUtils; }()); var MonocleLayout = (function () { function MonocleLayout() { this.description = "Monocle"; this.classID = MonocleLayout.id; } MonocleLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tile) { tile.state = CONFIG.monocleMaximize ? WindowState.Maximized : WindowState.Tiled; tile.geometry = area; }); if (ctx.backend === KWinDriver.backendName && KWINCONFIG.monocleMinimizeRest) { var tiles_1 = __spreadArray([], tileables, true); ctx.setTimeout(function () { var current = ctx.currentWindow; if (current && current.tiled) { tiles_1.forEach(function (window) { if (window !== current) window.window.window.minimized = true; }); } }, 50); } }; MonocleLayout.prototype.clone = function () { return this; }; MonocleLayout.prototype.handleShortcut = function (ctx, input, data) { switch (input) { case Shortcut.DWMLeft: case Shortcut.FocusNext: case Shortcut.FocusUp: case Shortcut.FocusLeft: ctx.cycleFocus(-1); return true; case Shortcut.DWMRight: case Shortcut.FocusPrev: case Shortcut.FocusDown: case Shortcut.FocusRight: ctx.cycleFocus(1); return true; default: return false; } }; MonocleLayout.prototype.toString = function () { return "MonocleLayout()"; }; MonocleLayout.id = "MonocleLayout"; return MonocleLayout; }()); var QuarterLayout = (function () { function QuarterLayout() { this.classID = QuarterLayout.id; this.description = "Quarter"; this.lhsplit = 0.5; this.rhsplit = 0.5; this.vsplit = 0.5; } Object.defineProperty(QuarterLayout.prototype, "capacity", { get: function () { return 4; }, enumerable: false, configurable: true }); QuarterLayout.prototype.adjust = function (area, tiles, basis, delta) { if (tiles.length <= 1 || tiles.length > 4) return; var idx = tiles.indexOf(basis); if (idx < 0) return; if ((idx === 0 || idx === 3) && delta.east !== 0) this.vsplit = (Math.floor(area.width * this.vsplit) + delta.east) / area.width; else if ((idx === 1 || idx === 2) && delta.west !== 0) this.vsplit = (Math.floor(area.width * this.vsplit) - delta.west) / area.width; if (tiles.length === 4) { if (idx === 0 && delta.south !== 0) this.lhsplit = (Math.floor(area.height * this.lhsplit) + delta.south) / area.height; if (idx === 3 && delta.north !== 0) this.lhsplit = (Math.floor(area.height * this.lhsplit) - delta.north) / area.height; } if (tiles.length >= 3) { if (idx === 1 && delta.south !== 0) this.rhsplit = (Math.floor(area.height * this.rhsplit) + delta.south) / area.height; if (idx === 2 && delta.north !== 0) this.rhsplit = (Math.floor(area.height * this.rhsplit) - delta.north) / area.height; } this.vsplit = clip(this.vsplit, 1 - QuarterLayout.MAX_PROPORTION, QuarterLayout.MAX_PROPORTION); this.lhsplit = clip(this.lhsplit, 1 - QuarterLayout.MAX_PROPORTION, QuarterLayout.MAX_PROPORTION); this.rhsplit = clip(this.rhsplit, 1 - QuarterLayout.MAX_PROPORTION, QuarterLayout.MAX_PROPORTION); }; QuarterLayout.prototype.clone = function () { var other = new QuarterLayout(); other.lhsplit = this.lhsplit; other.rhsplit = this.rhsplit; other.vsplit = this.vsplit; return other; }; QuarterLayout.prototype.apply = function (ctx, tileables, area) { for (var i = 0; i < 4 && i < tileables.length; i++) tileables[i].state = WindowState.Tiled; if (tileables.length > 4) tileables .slice(4) .forEach(function (tile) { return (tile.state = WindowState.TiledAfloat); }); if (tileables.length === 1) { tileables[0].geometry = area; return; } var gap1 = Math.floor(CONFIG.tileLayoutGap / 2); var gap2 = CONFIG.tileLayoutGap - gap1; var leftWidth = Math.floor(area.width * this.vsplit); var rightWidth = area.width - leftWidth; var rightX = area.x + leftWidth; if (tileables.length === 2) { tileables[0].geometry = new Rect(area.x, area.y, leftWidth, area.height).gap(0, gap1, 0, 0); tileables[1].geometry = new Rect(rightX, area.y, rightWidth, area.height).gap(gap2, 0, 0, 0); return; } var rightTopHeight = Math.floor(area.height * this.rhsplit); var rightBottomHeight = area.height - rightTopHeight; var rightBottomY = area.y + rightTopHeight; if (tileables.length === 3) { tileables[0].geometry = new Rect(area.x, area.y, leftWidth, area.height).gap(0, gap1, 0, 0); tileables[1].geometry = new Rect(rightX, area.y, rightWidth, rightTopHeight).gap(gap2, 0, 0, gap1); tileables[2].geometry = new Rect(rightX, rightBottomY, rightWidth, rightBottomHeight).gap(gap2, 0, gap2, 0); return; } var leftTopHeight = Math.floor(area.height * this.lhsplit); var leftBottomHeight = area.height - leftTopHeight; var leftBottomY = area.y + leftTopHeight; if (tileables.length >= 4) { tileables[0].geometry = new Rect(area.x, area.y, leftWidth, leftTopHeight).gap(0, gap1, 0, gap1); tileables[1].geometry = new Rect(rightX, area.y, rightWidth, rightTopHeight).gap(gap2, 0, 0, gap1); tileables[2].geometry = new Rect(rightX, rightBottomY, rightWidth, rightBottomHeight).gap(gap2, 0, gap2, 0); tileables[3].geometry = new Rect(area.x, leftBottomY, leftWidth, leftBottomHeight).gap(0, gap2, gap2, 0); } }; QuarterLayout.prototype.toString = function () { return "QuarterLayout()"; }; QuarterLayout.MAX_PROPORTION = 0.8; QuarterLayout.id = "QuarterLayout"; return QuarterLayout; }()); var SpiralLayout = (function () { function SpiralLayout() { this.description = "Spiral"; this.classID = SpiralLayout.id; this.depth = 1; this.parts = new HalfSplitLayoutPart(new FillLayoutPart(), new FillLayoutPart()); this.parts.angle = 0; this.parts.gap = CONFIG.tileLayoutGap; } SpiralLayout.prototype.adjust = function (area, tiles, basis, delta) { this.parts.adjust(area, tiles, basis, delta); }; SpiralLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); this.bore(tileables.length); this.parts.apply(area, tileables).forEach(function (geometry, i) { tileables[i].geometry = geometry; }); }; SpiralLayout.prototype.toString = function () { return "Spiral()"; }; SpiralLayout.prototype.bore = function (depth) { if (this.depth >= depth) return; var hpart = this.parts; var i; for (i = 0; i < this.depth - 1; i++) { hpart = hpart.secondary; } var lastFillPart = hpart.secondary; var npart; while (i < depth - 1) { npart = new HalfSplitLayoutPart(new FillLayoutPart(), lastFillPart); npart.gap = CONFIG.tileLayoutGap; switch ((i + 1) % 4) { case 0: npart.angle = 0; break; case 1: npart.angle = 90; break; case 2: npart.angle = 180; break; case 3: npart.angle = 270; break; } hpart.secondary = npart; hpart = npart; i++; } this.depth = depth; }; SpiralLayout.id = "SpiralLayout"; return SpiralLayout; }()); var SpreadLayout = (function () { function SpreadLayout() { this.classID = SpreadLayout.id; this.description = "Spread"; this.space = 0.07; } SpreadLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); var tiles = tileables; var numTiles = tiles.length; var spaceWidth = Math.floor(area.width * this.space); var cardWidth = area.width - spaceWidth * (numTiles - 1); var miniumCardWidth = area.width * 0.4; while (cardWidth < miniumCardWidth) { cardWidth += spaceWidth; numTiles -= 1; } for (var i = 0; i < tiles.length; i++) tiles[i].geometry = new Rect(area.x + (i < numTiles ? spaceWidth * (numTiles - i - 1) : 0), area.y, cardWidth, area.height); }; SpreadLayout.prototype.clone = function () { var other = new SpreadLayout(); other.space = this.space; return other; }; SpreadLayout.prototype.handleShortcut = function (ctx, input) { switch (input) { case Shortcut.Decrease: this.space = Math.max(0.04, this.space - 0.01); break; case Shortcut.Increase: this.space = Math.min(0.1, this.space + 0.01); break; default: return false; } return true; }; SpreadLayout.prototype.toString = function () { return "SpreadLayout(" + this.space + ")"; }; SpreadLayout.id = "SpreadLayout"; return SpreadLayout; }()); var StackedLayout = (function () { function StackedLayout() { this.classID = StackedLayout.id; this.parts = new RotateLayoutPart(new HalfSplitLayoutPart(new StackLayoutPart(), new StackLayoutPart())); var masterPart = this.parts.inner; masterPart.gap = masterPart.secondary.gap = CONFIG.tileLayoutGap; } Object.defineProperty(StackedLayout.prototype, "description", { get: function () { return "Stacked"; }, enumerable: false, configurable: true }); StackedLayout.prototype.adjust = function (area, tiles, basis, delta) { this.parts.adjust(area, tiles, basis, delta); }; StackedLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); if (tileables.length > 1) { this.parts.inner.angle = 90; } this.parts.apply(area, tileables).forEach(function (geometry, i) { tileables[i].geometry = geometry; }); }; StackedLayout.prototype.clone = function () { var other = new StackedLayout(); return other; }; StackedLayout.prototype.handleShortcut = function (ctx, input) { switch (input) { case Shortcut.Rotate: this.parts.rotate(90); break; default: return false; } return true; }; StackedLayout.prototype.toString = function () { return ("StackedLayout()"); }; StackedLayout.id = "StackedLayout"; return StackedLayout; }()); var StairLayout = (function () { function StairLayout() { this.classID = StairLayout.id; this.description = "Stair"; this.space = 24; } StairLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); var tiles = tileables; var len = tiles.length; var space = this.space; var alignRight = Number(!KWINCONFIG.stairReverse); for (var i = 0; i < len; i++) { var dx = space * (len - i - 1); var dy = space * i; tiles[i].geometry = new Rect(area.x + alignRight * dx, area.y + dy, area.width - dx, area.height - dy); } }; StairLayout.prototype.clone = function () { var other = new StairLayout(); other.space = this.space; return other; }; StairLayout.prototype.handleShortcut = function (ctx, input) { switch (input) { case Shortcut.Decrease: this.space = Math.max(16, this.space - 8); break; case Shortcut.Increase: this.space = Math.min(160, this.space + 8); break; default: return false; } return true; }; StairLayout.prototype.toString = function () { return "StairLayout(" + this.space + ")"; }; StairLayout.id = "StairLayout"; return StairLayout; }()); var ThreeColumnLayout = (function () { function ThreeColumnLayout() { this.classID = ThreeColumnLayout.id; this.masterRatio = 0.6; this.masterSize = 1; } Object.defineProperty(ThreeColumnLayout.prototype, "description", { get: function () { return "Three-Column [" + this.masterSize + "]"; }, enumerable: false, configurable: true }); ThreeColumnLayout.prototype.adjust = function (area, tiles, basis, delta) { var basisIndex = tiles.indexOf(basis); if (basisIndex < 0) return; if (tiles.length === 0) return; else if (tiles.length <= this.masterSize) { LayoutUtils.adjustAreaWeights(area, tiles.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap, tiles.indexOf(basis), delta).forEach(function (newWeight, i) { return (tiles[i].weight = newWeight * tiles.length); }); } else if (tiles.length === this.masterSize + 1) { this.masterRatio = LayoutUtils.adjustAreaHalfWeights(area, this.masterRatio, CONFIG.tileLayoutGap, basisIndex < this.masterSize ? 0 : 1, delta, true); if (basisIndex < this.masterSize) { var masterTiles_1 = tiles.slice(0, -1); LayoutUtils.adjustAreaWeights(area, masterTiles_1.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap, basisIndex, delta).forEach(function (newWeight, i) { return (masterTiles_1[i].weight = newWeight * masterTiles_1.length); }); } } else if (tiles.length > this.masterSize + 1) { var basisGroup = void 0; if (basisIndex < this.masterSize) basisGroup = 1; else if (basisIndex < Math.floor((this.masterSize + tiles.length) / 2)) basisGroup = 2; else basisGroup = 0; var stackRatio = 1 - this.masterRatio; var newRatios = LayoutUtils.adjustAreaWeights(area, [stackRatio, this.masterRatio, stackRatio], CONFIG.tileLayoutGap, basisGroup, delta, true); var newMasterRatio = newRatios[1]; var newStackRatio = basisGroup === 0 ? newRatios[0] : newRatios[2]; this.masterRatio = newMasterRatio / (newMasterRatio + newStackRatio); var rstackNumTile = Math.floor((tiles.length - this.masterSize) / 2); var _a = partitionArrayBySizes(tiles, [ this.masterSize, rstackNumTile, ]), masterTiles = _a[0], rstackTiles = _a[1], lstackTiles = _a[2]; var groupTiles_1 = [lstackTiles, masterTiles, rstackTiles][basisGroup]; LayoutUtils.adjustAreaWeights(area, groupTiles_1.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap, groupTiles_1.indexOf(basis), delta).forEach(function (newWeight, i) { return (groupTiles_1[i].weight = newWeight * groupTiles_1.length); }); } }; ThreeColumnLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); var tiles = tileables; if (tiles.length <= this.masterSize) { LayoutUtils.splitAreaWeighted(area, tiles.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap).forEach(function (tileArea, i) { return (tiles[i].geometry = tileArea); }); } else if (tiles.length === this.masterSize + 1) { var _a = LayoutUtils.splitAreaHalfWeighted(area, this.masterRatio, CONFIG.tileLayoutGap, true), masterArea = _a[0], stackArea = _a[1]; var masterTiles_2 = tiles.slice(0, this.masterSize); LayoutUtils.splitAreaWeighted(masterArea, masterTiles_2.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap).forEach(function (tileArea, i) { return (masterTiles_2[i].geometry = tileArea); }); tiles[tiles.length - 1].geometry = stackArea; } else if (tiles.length > this.masterSize + 1) { var stackRatio = 1 - this.masterRatio; var groupAreas_1 = LayoutUtils.splitAreaWeighted(area, [stackRatio, this.masterRatio, stackRatio], CONFIG.tileLayoutGap, true); var rstackSize = Math.floor((tiles.length - this.masterSize) / 2); var _b = partitionArrayBySizes(tiles, [ this.masterSize, rstackSize, ]), masterTiles = _b[0], rstackTiles = _b[1], lstackTiles = _b[2]; [lstackTiles, masterTiles, rstackTiles].forEach(function (groupTiles, group) { LayoutUtils.splitAreaWeighted(groupAreas_1[group], groupTiles.map(function (tile) { return tile.weight; }), CONFIG.tileLayoutGap).forEach(function (tileArea, i) { return (groupTiles[i].geometry = tileArea); }); }); } }; ThreeColumnLayout.prototype.clone = function () { var other = new ThreeColumnLayout(); other.masterRatio = this.masterRatio; other.masterSize = this.masterSize; return other; }; ThreeColumnLayout.prototype.handleShortcut = function (ctx, input, data) { switch (input) { case Shortcut.Increase: this.resizeMaster(ctx, +1); return true; case Shortcut.Decrease: this.resizeMaster(ctx, -1); return true; case Shortcut.DWMLeft: this.masterRatio = clip(slide(this.masterRatio, -0.05), ThreeColumnLayout.MIN_MASTER_RATIO, ThreeColumnLayout.MAX_MASTER_RATIO); return true; case Shortcut.DWMRight: this.masterRatio = clip(slide(this.masterRatio, +0.05), ThreeColumnLayout.MIN_MASTER_RATIO, ThreeColumnLayout.MAX_MASTER_RATIO); return true; default: return false; } }; ThreeColumnLayout.prototype.toString = function () { return "ThreeColumnLayout(nmaster=" + this.masterSize + ")"; }; ThreeColumnLayout.prototype.resizeMaster = function (ctx, step) { this.masterSize = clip(this.masterSize + step, 1, 10); ctx.showNotification(this.description); }; ThreeColumnLayout.MIN_MASTER_RATIO = 0.2; ThreeColumnLayout.MAX_MASTER_RATIO = 0.75; ThreeColumnLayout.id = "ThreeColumnLayout"; return ThreeColumnLayout; }()); var TileLayout = (function () { function TileLayout() { this.classID = TileLayout.id; this.parts = new RotateLayoutPart(new HalfSplitLayoutPart(new RotateLayoutPart(new StackLayoutPart()), new StackLayoutPart())); var masterPart = this.parts.inner; masterPart.gap = masterPart.primary.inner.gap = masterPart.secondary.gap = CONFIG.tileLayoutGap; } Object.defineProperty(TileLayout.prototype, "description", { get: function () { return "Tile [" + this.numMaster + "]"; }, enumerable: false, configurable: true }); Object.defineProperty(TileLayout.prototype, "numMaster", { get: function () { return this.parts.inner.primarySize; }, set: function (value) { this.parts.inner.primarySize = value; }, enumerable: false, configurable: true }); Object.defineProperty(TileLayout.prototype, "masterRatio", { get: function () { return this.parts.inner.ratio; }, set: function (value) { this.parts.inner.ratio = value; }, enumerable: false, configurable: true }); TileLayout.prototype.adjust = function (area, tiles, basis, delta) { this.parts.adjust(area, tiles, basis, delta); }; TileLayout.prototype.apply = function (ctx, tileables, area) { tileables.forEach(function (tileable) { return (tileable.state = WindowState.Tiled); }); this.parts.apply(area, tileables).forEach(function (geometry, i) { tileables[i].geometry = geometry; }); }; TileLayout.prototype.clone = function () { var other = new TileLayout(); other.masterRatio = this.masterRatio; other.numMaster = this.numMaster; return other; }; TileLayout.prototype.handleShortcut = function (ctx, input) { switch (input) { case Shortcut.DWMLeft: this.masterRatio = clip(slide(this.masterRatio, -0.05), TileLayout.MIN_MASTER_RATIO, TileLayout.MAX_MASTER_RATIO); break; case Shortcut.DWMRight: this.masterRatio = clip(slide(this.masterRatio, +0.05), TileLayout.MIN_MASTER_RATIO, TileLayout.MAX_MASTER_RATIO); break; case Shortcut.Increase: if (this.numMaster < 10) this.numMaster += 1; ctx.showNotification(this.description); break; case Shortcut.Decrease: if (this.numMaster > 0) this.numMaster -= 1; ctx.showNotification(this.description); break; case Shortcut.Rotate: this.parts.rotate(90); break; case Shortcut.RotatePart: this.parts.inner.primary.rotate(90); break; default: return false; } return true; }; TileLayout.prototype.toString = function () { return ("TileLayout(nmaster=" + this.numMaster + ", ratio=" + this.masterRatio + ")"); }; TileLayout.MIN_MASTER_RATIO = 0.2; TileLayout.MAX_MASTER_RATIO = 0.8; TileLayout.id = "TileLayout"; return TileLayout; }()); var DEBUG = { enabled: false, started: new Date().getTime(), }; function debug(f) { if (DEBUG.enabled) { var timestamp = (new Date().getTime() - DEBUG.started) / 1000; console.log("[" + timestamp + "]", f()); } } function debugObj(f) { if (DEBUG.enabled) { var timestamp = (new Date().getTime() - DEBUG.started) / 1000; var _a = f(), name = _a[0], obj = _a[1]; var buf = []; for (var i in obj) buf.push(i + "=" + obj[i]); console.log("[" + timestamp + "]", name + ": " + buf.join(" ")); } } function clip(value, min, max) { if (value < min) return min; if (value > max) return max; return value; } function slide(value, step) { if (step === 0) return value; return Math.floor(value / step + 1.000001) * step; } function matchWords(str, words) { for (var i = 0; i < words.length; i++) { if (str.indexOf(words[i]) >= 0) return i; } return -1; } function wrapIndex(index, length) { if (index < 0) return index + length; if (index >= length) return index - length; return index; } function partitionArray(array, predicate) { return array.reduce(function (parts, item, index) { parts[predicate(item, index) ? 0 : 1].push(item); return parts; }, [[], []]); } function partitionArrayBySizes(array, sizes) { var base = 0; var chunks = sizes.map(function (size) { var chunk = array.slice(base, base + size); base += size; return chunk; }); chunks.push(array.slice(base)); return chunks; } function overlap(min1, max1, min2, max2) { var min = Math.min; var max = Math.max; var dx = max(0, min(max1, max2) - max(min1, min2)); return dx > 0; } function toQRect(rect) { return Qt.rect(rect.x, rect.y, rect.width, rect.height); } function toRect(qrect) { return new Rect(qrect.x, qrect.y, qrect.width, qrect.height); } var Rect = (function () { function Rect(x, y, width, height) { this.x = x; this.y = y; this.width = width; this.height = height; } Object.defineProperty(Rect.prototype, "maxX", { get: function () { return this.x + this.width; }, enumerable: false, configurable: true }); Object.defineProperty(Rect.prototype, "maxY", { get: function () { return this.y + this.height; }, enumerable: false, configurable: true }); Object.defineProperty(Rect.prototype, "center", { get: function () { return [ this.x + Math.floor(this.width / 2), this.y + Math.floor(this.height / 2), ]; }, enumerable: false, configurable: true }); Rect.prototype.clone = function () { return new Rect(this.x, this.y, this.width, this.height); }; Rect.prototype.equals = function (other) { return (this.x === other.x && this.y === other.y && this.width === other.width && this.height === other.height); }; Rect.prototype.gap = function (left, right, top, bottom) { return new Rect(this.x + left, this.y + top, this.width - (left + right), this.height - (top + bottom)); }; Rect.prototype.gap_mut = function (left, right, top, bottom) { this.x += left; this.y += top; this.width -= left + right; this.height -= top + bottom; return this; }; Rect.prototype.includes = function (other) { return (this.x <= other.x && this.y <= other.y && other.maxX < this.maxX && other.maxY < this.maxY); }; Rect.prototype.includesPoint = function (_a) { var x = _a[0], y = _a[1]; return this.x <= x && x <= this.maxX && this.y <= y && y <= this.maxY; }; Rect.prototype.subtract = function (other) { return new Rect(this.x - other.x, this.y - other.y, this.width - other.width, this.height - other.height); }; Rect.prototype.toString = function () { return "Rect(" + [this.x, this.y, this.width, this.height].join(", ") + ")"; }; return Rect; }()); var RectDelta = (function () { function RectDelta(east, west, south, north) { this.east = east; this.west = west; this.south = south; this.north = north; } RectDelta.fromRects = function (basis, target) { var diff = target.subtract(basis); return new RectDelta(diff.width + diff.x, -diff.x, diff.height + diff.y, -diff.y); }; RectDelta.prototype.toString = function () { return ("WindowResizeDelta(" + [ "east=" + this.east, "west=" + this.west, "north=" + this.north, "south=" + this.south, ].join(" ") + ")"); }; return RectDelta; }()); var WrapperMap = (function () { function WrapperMap(hasher, wrapper) { this.hasher = hasher; this.wrapper = wrapper; this.items = {}; } WrapperMap.prototype.add = function (item) { var key = this.hasher(item); if (this.items[key] !== undefined) throw "WrapperMap: the key [" + key + "] already exists!"; var wrapped = this.wrapper(item); this.items[key] = wrapped; return wrapped; }; WrapperMap.prototype.get = function (item) { var key = this.hasher(item); return this.items[key] || null; }; WrapperMap.prototype.getByKey = function (key) { return this.items[key] || null; }; WrapperMap.prototype.remove = function (item) { var key = this.hasher(item); return delete this.items[key]; }; WrapperMap.prototype.length = function () { return Object.keys(this.items).length; }; return WrapperMap; }());