From f982ce32d2ea5b8cfcaea5b8c42466c2e8267607 Mon Sep 17 00:00:00 2001 From: Vangelis Tasoulas Date: Mon, 4 Mar 2024 20:53:03 +0100 Subject: [PATCH 1/4] Added functionality to shrink/grow and move windows left/right/up/down Registers the following additional shortcuts: * IncreaseWindowSize: Ctrl+Meta+Num++ * DecreaseWindowSize: Ctrl+Meta+Num+- * MoveWindowLeft: Ctrl+Meta+Left * MoveWindowRight: Ctrl+Meta+Right * MoveWindowUp: Ctrl+Meta+Up * MoveWindowDown: Ctrl+Meta+Down --- contents/code/main.js | 181 ++++++++++++++++++++++++++++++++++++++++++ scripts/debug.sh | 4 + 2 files changed, 185 insertions(+) diff --git a/contents/code/main.js b/contents/code/main.js index 9f1bcd0..f29fdaf 100644 --- a/contents/code/main.js +++ b/contents/code/main.js @@ -43,6 +43,163 @@ function center(workspace) { } } +function ensureWithinVisibleArea(client, new_w, new_h, old_w, old_h, old_x, old_y) { + var new_x, new_y; + var maxArea = workspace.clientArea(KWin.MaximizeArea, client); + var ratio = new_w / new_h; + + var diff_x = old_w - new_w, + diff_y = old_h - new_h; + + // Calculate a new x and y that will keep the position + // of the window centered with respect to its previous + // position + new_x = old_x + Math.round(diff_x / 2); + new_y = old_y + Math.round(diff_y / 2); + + // Ensure the newly calculate position is within the boundaries + // of the visible desktop area + if (new_y + new_h > maxArea.bottom) { + new_y = new_y - ((new_y + new_h) - maxArea.bottom); + } + if (new_x + new_w > maxArea.right) { + new_x = new_x - ((new_x + new_w) - maxArea.right); + } + + // Also ensure that new_x and new_y is never less than 0 + new_x = new_x < 0 ? 0 : new_x; + new_y = new_y < 0 ? 0 : new_y; + + return {"x": new_x, "y": new_y, "w": new_w, "h": new_h}; +} + +function calcShrink(client, decStepPx, minSizePx) { + var geom = client.frameGeometry; + var maxArea = workspace.clientArea(KWin.MaximizeArea, client); + + var ratio = geom.width / geom.height; + var new_w, new_h; + var new_xywh = {"x": geom.x, "y": geom.y, "w": geom.width, "h": geom.height}; + + // Ensure the minSizePx is smaller than maxArea width/height + minSizePx = minSizePx > maxArea.width ? maxArea.width : minSizePx; + minSizePx = minSizePx > maxArea.height ? maxArea.height : minSizePx; + + if (client.moveable && client.resizeable) { + if (ratio >= 1) { + // Width >= Height + new_w = geom.width - decStepPx; + new_w = new_w < minSizePx ? minSizePx : new_w; + new_h = Math.round(new_w / ratio); + + if (new_h > maxArea.height) { + new_h = maxArea.height + new_w = Math.round(new_h * ratio); + } + } else { + // Height > Width + new_h = geom.height - decStepPx; + new_h = new_h < minSizePx ? minSizePx : new_h; + new_w = Math.round(new_h * ratio); + + if (new_w > maxArea.width) { + new_w = maxArea.width + new_h = Math.round(new_w / ratio); + } + } + + new_xywh = ensureWithinVisibleArea(client, new_w, new_h, geom.width, geom.height, geom.x, geom.y) + } + + return {"x": new_xywh.x, "y": new_xywh.y, "w": new_xywh.w, "h": new_xywh.h}; +} + +function calcGrow(client, incStepPx) { + var geom = client.frameGeometry; + var maxArea = workspace.clientArea(KWin.MaximizeArea, client); + + var ratio = geom.width / geom.height; + var new_w, new_h; + var new_xywh = {"x": geom.x, "y": geom.y, "w": geom.width, "h": geom.height}; + + if (client.moveable && client.resizeable) { + if (ratio >= 1) { + // Width >= Height + new_w = geom.width + incStepPx; + new_w = new_w > maxArea.width ? maxArea.width : new_w; + new_h = Math.round(new_w / ratio); + + if (new_h > maxArea.height) { + new_h = maxArea.height + new_w = Math.round(new_h * ratio); + } + } else { + // Height > Width + new_h = geom.height + incStepPx; + new_h = new_h > maxArea.height ? maxArea.height : new_h; + new_w = Math.round(new_h * ratio); + + if (new_w > maxArea.width) { + new_w = maxArea.width + new_h = Math.round(new_w / ratio); + } + } + + new_xywh = ensureWithinVisibleArea(client, new_w, new_h, geom.width, geom.height, geom.x, geom.y) + } + + return {"x": new_xywh.x, "y": new_xywh.y, "w": new_xywh.w, "h": new_xywh.h}; +} + +function resize(workspace, action, incStepPx, minSizePx) { + var client = workspace.activeWindow; + + if (client.moveable && client.resizeable) { + var geom = client.frameGeometry; + var newGeom; + + var x = geom.x, + y = geom.y, + w = geom.width, + h = geom.height, + ratio = geom.width / geom.height; + + if (action == "shrink") { + newGeom = calcShrink(client, incStepPx, minSizePx); + } else if (action == "grow") { + newGeom = calcGrow(client, incStepPx); + } else { + print("Please choose an action between 'shrink' and 'grow'"); + } + + // print(client.resourceName, JSON.stringify(newGeom)); + + reposition(client, newGeom.x, newGeom.y, newGeom.w, newGeom.h); + } +} + +function moveWithFixedSize(workspace, moveDirection, movePx) { + var client = workspace.activeWindow; + var geom = client.frameGeometry; + var x = geom.x, + y = geom.y; + if (client.moveable) { + if (moveDirection == "left") { + x = geom.x - movePx; + } else if (moveDirection == "right") { + x = geom.x + movePx; + } else if (moveDirection == "up") { + y = geom.y - movePx; + } else if (moveDirection == "down") { + y = geom.y + movePx; + } else { + print("Please choose a move direction between 'left', 'right', 'up' and 'down'"); + } + new_xy = ensureWithinVisibleArea(client, geom.width, geom.height, geom.width, geom.height, x, y); + reposition(client, new_xy.x, new_xy.y, geom.width, geom.height); + } +} + // function isInPosition(workspace, numberXslots, numberYslots, x, y, xSlotToFill, ySlotToFill) { // var client = workspace.activeWindow; // if (client.moveable) { @@ -274,3 +431,27 @@ registerShortcut("MoveWindowToCenter", "UltrawideWindows: Center Window", "ctrl+ registerShortcut("MoveWindowToCenter1", "UltrawideWindows: Center Window (copy)", "alt+Num+5", function () { center(workspace) }); + +registerShortcut("IncreaseWindowSize", "UltrawideWindows: Increase the window size in place", "Ctrl+Meta+Num++", function () { + resize(workspace, "grow", 20, 0); +}); + +registerShortcut("DecreaseWindowSize", "UltrawideWindows: Decrease the window size in place", "Ctrl+Meta+Num+-", function () { + resize(workspace, "shrink", 20, 300); +}); + +registerShortcut("MoveWindowLeft", "UltrawideWindows: Move the window to the left", "Ctrl+Meta+Left", function () { + moveWithFixedSize(workspace, "left", 20); +}); + +registerShortcut("MoveWindowRight", "UltrawideWindows: Move the window to the right", "Ctrl+Meta+Right", function () { + moveWithFixedSize(workspace, "right", 20); +}); + +registerShortcut("MoveWindowUp", "UltrawideWindows: Move the window up", "Ctrl+Meta+Up", function () { + moveWithFixedSize(workspace, "up", 20); +}); + +registerShortcut("MoveWindowDown", "UltrawideWindows: Move the window down", "Ctrl+Meta+Down", function () { + moveWithFixedSize(workspace, "down", 20); +}); diff --git a/scripts/debug.sh b/scripts/debug.sh index 48e2799..d9e20cd 100755 --- a/scripts/debug.sh +++ b/scripts/debug.sh @@ -1,3 +1,7 @@ #!/bin/sh # https://develop.kde.org/docs/plasma/kwin/ +# +# To see the debug output when developing, in separate terminal +# run the command: +# journalctl -f QT_CATEGORY=js QT_CATEGORY=kwin_scripting plasma-interactiveconsole --kwin From 511270d7ac07cec12db38ad10ffe628a58c2584d Mon Sep 17 00:00:00 2001 From: Vangelis Tasoulas Date: Mon, 4 Mar 2024 21:09:06 +0100 Subject: [PATCH 2/4] Updated README --- README.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a237464..a710728 100644 --- a/README.md +++ b/README.md @@ -79,15 +79,21 @@ My suggestion is to use the following configuration: | alt + Meta + Numpad5 | UltrawideWindows: Move Window to center-height 2/3 width (center biased) | | alt + Meta + Numpad6 | UltrawideWindows: Move Window to right-height 2/3 width (center biased) | -| Shortcuts | General commands (easy to use) | -| ------------------------------------------------------ | ---------------------------------------------------- | -| Meta + Numpad0 | UltrawideWindows: Maximize Window | -| Alt + Numpad0 | UltrawideWindows: Maximize Window (copy) | -| Ctrl+ Numpad0 | UltrawideWindows: Maximize Window (copy2) | -| Ctrl + Meta + Numpad0 | UltrawideWindows: Maximize Window (copy3) | -| Alt + Meta + Numpad0 | UltrawideWindows: Maximize Window (copy4) | -| Alt + Numpad5 | UltrawideWindows: Center Window | -| Ctrl + Numpad5 | UltrawideWindows: Center Window (copy) | +| Shortcuts | General commands (easy to use) | +| ------------------------------------------------------ | ---------------------------------------------------------------------------- | +| Meta + Numpad0 | UltrawideWindows: Maximize Window | +| Alt + Numpad0 | UltrawideWindows: Maximize Window (copy) | +| Ctrl+ Numpad0 | UltrawideWindows: Maximize Window (copy2) | +| Ctrl + Meta + Numpad0 | UltrawideWindows: Maximize Window (copy3) | +| Alt + Meta + Numpad0 | UltrawideWindows: Maximize Window (copy4) | +| Alt + Numpad5 | UltrawideWindows: Center Window | +| Ctrl + Numpad5 | UltrawideWindows: Center Window (copy) | +| Ctrl + Meta + Numpad+ | UltrawideWindows: Increase Window Size by 20px - Maintains aspect ratio | +| Ctrl + Meta + Numpad- | UltrawideWindows: Decrease Window Size by 20px - Maintains aspect ratio | +| Ctrl + Meta + Left | UltrawideWindows: Move Window Left by 20px | +| Ctrl + Meta + Right | UltrawideWindows: Move Window Right by 20px | +| Ctrl + Meta + Up | UltrawideWindows: Move Window Up by 20px | +| Ctrl + Meta + Down | UltrawideWindows: Move Window Down by 20px | From 393bac1d576bda2c5038901cfa26f3ea8e8765ab Mon Sep 17 00:00:00 2001 From: Vangelis Tasoulas Date: Fri, 22 Mar 2024 17:17:45 +0100 Subject: [PATCH 3/4] Metadata.desktop is not needed any more - remove The metadata.json file is the recommended way to go as per the latest KWIN scripting tutorial: https://develop.kde.org/docs/plasma/kwin/ --- metadata.desktop | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 metadata.desktop diff --git a/metadata.desktop b/metadata.desktop deleted file mode 100644 index aa1d36f..0000000 --- a/metadata.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Name=Ultrawide Windows -Comment=Move windows in useful positions in a ultrawide monitor -Icon=preferences-system-windows-script-test - -X-Plasma-API=javascript -X-Plasma-MainScript=code/main.js - -X-KDE-PluginInfo-Author=Luca Moschella -X-KDE-PluginInfo-Email=nopaste94@gmail.com -X-KDE-PluginInfo-Name=ultrawidewindows -X-KDE-PluginInfo-Version=4.0 -X-KDE-PluginInfo-EnabledByDefault=true - -X-KDE-PluginInfo-Depends= -X-KDE-PluginInfo-License=GPL -X-KDE-ServiceTypes=KWin/Script -Type=Service From d4ee12ef8f31484f3f54bf9fc3e8d51c5108a1ae Mon Sep 17 00:00:00 2001 From: Vangelis Tasoulas Date: Fri, 22 Mar 2024 17:38:50 +0100 Subject: [PATCH 4/4] Remove some dead code --- contents/code/main.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/contents/code/main.js b/contents/code/main.js index f29fdaf..8fbb468 100644 --- a/contents/code/main.js +++ b/contents/code/main.js @@ -155,21 +155,15 @@ function resize(workspace, action, incStepPx, minSizePx) { var client = workspace.activeWindow; if (client.moveable && client.resizeable) { - var geom = client.frameGeometry; var newGeom; - var x = geom.x, - y = geom.y, - w = geom.width, - h = geom.height, - ratio = geom.width / geom.height; - if (action == "shrink") { newGeom = calcShrink(client, incStepPx, minSizePx); } else if (action == "grow") { newGeom = calcGrow(client, incStepPx); } else { print("Please choose an action between 'shrink' and 'grow'"); + return; } // print(client.resourceName, JSON.stringify(newGeom)); @@ -194,6 +188,7 @@ function moveWithFixedSize(workspace, moveDirection, movePx) { y = geom.y + movePx; } else { print("Please choose a move direction between 'left', 'right', 'up' and 'down'"); + return; } new_xy = ensureWithinVisibleArea(client, geom.width, geom.height, geom.width, geom.height, x, y); reposition(client, new_xy.x, new_xy.y, geom.width, geom.height);