diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/.gitignore b/.gitignore
index 355ba59..17f0e79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
*.kwinscript
+.direnv/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..111a532
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+install:
+ kpackagetool6 --type=KWin/Script -i .
+
+update:
+ kpackagetool6 --type=KWin/Script -u .
+
+package:
+ zip -r quick-tile-2-v$$(cat metadata.json | jq -r .KPlugin.Version).kwinscript contents/* LICENSE README.md metadata.json
diff --git a/README.md b/README.md
index 60f39b6..7643090 100644
--- a/README.md
+++ b/README.md
@@ -17,27 +17,28 @@ _or_ [download the zip](https://github.com/tsoernes/kwin-quick-tile-2/releases)
2. `cd` into the `kwin-quick-tile-2` folder.
3. Execute the following command in the `kwin-quick-tile-2` folder:
-```
-sh install.sh
-```
+ ```
+ make install
+ ```
+
+ If the extension was already installed before, use the following instead:
+ ```
+ make update
+ ```
+
4. Open `KWin Scripts` from the start menu and enable Quick Tile 2.
+
## How to use
Default keys are , for example , as in Windows 10, where the Meta key is also known as the Super key or Windows key.
If the keys are already bound, you need to set them in "Global Shortcuts" from the start menu. The shortcuts are prefixed "Quick Tile 2".
They are usually to be found in the KWin shortcut tab, but on some systems they end up in the System Settings tab.
-## Manual installation and packaging
+## Packaging
-Should something go wrong with the above script, you can try to manually package and install it.
To package this kwin-script into a .kwinscript archive, execute:
```
-zip -r quick-tile-2-v$(cat metadata.desktop | grep X-KDE-PluginInfo-Version= | awk -F'=' '{print $2}').kwinscript *
+make package
```
-To install the archive, execute:
-```
-plasmapkg2 --type kwinscript -i quick-tile-2-v*.kwinscript
-```
-Alternatively, open "KWin scripts" from the start menu and then "Import KWin script ..."
-Afterwards, you might need to log in and out.
+It can then be installed via "Import KWin script ..." in system settings.
diff --git a/contents/code/main.js b/contents/code/main.js
index 77648c0..43a3dec 100644
--- a/contents/code/main.js
+++ b/contents/code/main.js
@@ -9,217 +9,208 @@
* https://github.com/tsoernes/kwin-quick-tile-2
******************************************************************************/
-function _GetScreenGeometry() {
- return workspace.clientArea(KWin.PlacementArea, workspace.activeScreen, workspace.Desktop)
-}
-
-function _GetClientGeometryOnScreen() {
- const clientGeometry = workspace.activeClient.geometry
- const screenGeometry = _GetScreenGeometry()
- const x = clientGeometry.x - screenGeometry.x
- const y = clientGeometry.y - screenGeometry.y
- return {x: x, y: y, width: clientGeometry.width, height: clientGeometry.height}
-}
-
-function _IsVerticallyMaximized() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.height === screenGeometry.height) {
- return true
- }
- return false
-}
-
-function _IsHorizontallyMaximized() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.width === screenGeometry.width) {
- return true
- }
- return false
-}
-
-function _IsMaximized() {
- return _IsHorizontallyMaximized() && _IsVerticallyMaximized()
-}
-
-function _IsTiledToTop() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.height === (screenGeometry.height / 2) && clientGeometry.y === 0) {
- return true
- }
- return false
-}
-
-function _IsTiledTop() {
- return _IsTiledToTop() && _IsHorizontallyMaximized()
-}
-
-function _IsTiledToBottom() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.height === (screenGeometry.height / 2) && clientGeometry.y === (screenGeometry.height / 2)) {
- return true
- }
- return false
-}
-
-function _IsTiledBottom() {
- return _IsTiledToBottom() && _IsHorizontallyMaximized()
-}
-
-function _IsTiledToLeft() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.width === (screenGeometry.width / 2) && clientGeometry.x === 0) {
- return true
- }
- return false
-}
-
-function _IsTiledLeft() {
- return _IsTiledToLeft() && _IsVerticallyMaximized()
-}
-
-function _IsTiledToRight() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.width === (screenGeometry.width / 2) && clientGeometry.x === (screenGeometry.width / 2)) {
- return true
- }
- return false
-}
-
-function _IsTiledRight() {
- return _IsTiledToRight() && _IsVerticallyMaximized()
-}
-
-function _IsTiledToQuadrant() {
- const screenGeometry = _GetScreenGeometry()
- const clientGeometry = _GetClientGeometryOnScreen()
- if (clientGeometry.width === (screenGeometry.width / 2) && clientGeometry.height === (screenGeometry.height/ 2)) {
- return true
- }
- return false
-}
-
-function _IsTiledTopLeft() {
- return _IsTiledToTop() && _IsTiledToLeft()
-}
-
-function _IsTiledTopRight() {
- return _IsTiledToTop() && _IsTiledToRight()
-}
-
-function _IsTiledBottomLeft() {
- return _IsTiledToBottom() && _IsTiledToLeft()
-}
-
-function _IsTiledBottomRight() {
- return _IsTiledToBottom() && _IsTiledToRight()
-}
-
-var QuickTileUp = function() {
- // L > TL
- if (_IsTiledLeft()) {
- workspace.slotWindowQuickTileTopLeft()
+function _tileEvaluator() {
+ return {
+ screenGeometry: workspace.clientArea(
+ KWin.PlacementArea,
+ workspace.activeScreen,
+ workspace.currentDesktop
+ ),
+ clientGeometry: workspace.activeWindow.frameGeometry,
+ tileGeometry: workspace.activeWindow.tile?.relativeGeometry,
+
+ isVerticallyMaximized() {
+ return (this.clientGeometry.height === this.screenGeometry.height);
+ },
+ isHorizontallyMaximized() {
+ return (this.clientGeometry.height === this.screenGeometry.height);
+ },
+ isMaximized() {
+ return this.isHorizontallyMaximized() && this.isVerticallyMaximized();
+ },
+
+ isTiledTop() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0 &&
+ this.tileGeometry.y === 0 &&
+ this.tileGeometry.width === 1 &&
+ this.tileGeometry.height === 0.5;
+ },
+ isTiledBottom() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0 &&
+ this.tileGeometry.y === 0.5 &&
+ this.tileGeometry.width === 1 &&
+ this.tileGeometry.height === 0.5;
+ },
+ isTiledLeft() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0 &&
+ this.tileGeometry.y === 0 &&
+ this.tileGeometry.width === 0.5 &&
+ this.tileGeometry.height === 1;
+ },
+ isTiledRight() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0.5 &&
+ this.tileGeometry.y === 0 &&
+ this.tileGeometry.width === 0.5 &&
+ this.tileGeometry.height === 1;
+ },
+ isTiledTopLeft() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0 &&
+ this.tileGeometry.y === 0 &&
+ this.tileGeometry.width === 0.5 &&
+ this.tileGeometry.height === 0.5;
+ },
+ isTiledTopRight() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0.5 &&
+ this.tileGeometry.y === 0 &&
+ this.tileGeometry.width === 0.5 &&
+ this.tileGeometry.height === 0.5;
+ },
+ isTiledBottomLeft() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0 &&
+ this.tileGeometry.y === 0.5 &&
+ this.tileGeometry.width === 0.5 &&
+ this.tileGeometry.height === 0.5;
+ },
+ isTiledBottomRight() {
+ return this.tileGeometry != null &&
+ this.tileGeometry.x === 0.5 &&
+ this.tileGeometry.y === 0.5 &&
+ this.tileGeometry.width === 0.5 &&
+ this.tileGeometry.height === 0.5;
+ },
+ }
+}
+
+var QuickTileUp = function () {
+ const tileEvaluator = _tileEvaluator();
+
+ // L > TL
+ if (tileEvaluator.isTiledLeft()) {
+ workspace.slotWindowQuickTileTopLeft();
// R > TR
- } else if (_IsTiledRight()) {
- workspace.slotWindowQuickTileTopRight()
+ } else if (tileEvaluator.isTiledRight()) {
+ workspace.slotWindowQuickTileTopRight();
// B > T
- } else if (_IsTiledBottom()) {
- workspace.slotWindowQuickTileTop()
+ } else if (tileEvaluator.isTiledBottom()) {
+ workspace.slotWindowQuickTileTop();
// BL > L
- } else if (_IsTiledBottomLeft()) {
- workspace.slotWindowQuickTileLeft()
+ } else if (tileEvaluator.isTiledBottomLeft()) {
+ workspace.slotWindowQuickTileLeft();
// BR > R
- } else if (_IsTiledBottomRight()) {
- workspace.slotWindowQuickTileRight()
+ } else if (tileEvaluator.isTiledBottomRight()) {
+ workspace.slotWindowQuickTileRight();
// M > T
// this is probaly no good for multi-monitor
- } else if (_IsMaximized()) {
- workspace.slotWindowQuickTileTop()
- workspace.slotWindowQuickTileTop()
- } else {
- workspace.slotWindowMaximize()
- }
-}
-
-var QuickTileDown = function() {
- // L > BL
- if (_IsTiledLeft()) {
- workspace.slotWindowQuickTileBottomLeft()
+ } else if (tileEvaluator.isMaximized()) {
+ workspace.slotWindowMaximize();
+ } else {
+ workspace.slotWindowMaximize();
+ }
+};
+
+var QuickTileDown = function () {
+ const tileEvaluator = _tileEvaluator();
+
+ // L > BL
+ if (tileEvaluator.isTiledLeft()) {
+ workspace.slotWindowQuickTileBottomLeft();
// R > BR
- } else if (_IsTiledRight()) {
- workspace.slotWindowQuickTileBottomRight()
+ } else if (tileEvaluator.isTiledRight()) {
+ workspace.slotWindowQuickTileBottomRight();
// T > B
- } else if (_IsTiledTop()) {
- workspace.slotWindowQuickTileBottom()
+ } else if (tileEvaluator.isTiledTop()) {
+ workspace.slotWindowQuickTileBottom();
// TL > L
- } else if (_IsTiledTopLeft()) {
- workspace.slotWindowQuickTileLeft()
+ } else if (tileEvaluator.isTiledTopLeft()) {
+ workspace.slotWindowQuickTileLeft();
// TR > R
- } else if (_IsTiledTopRight()) {
- workspace.slotWindowQuickTileRight()
+ } else if (tileEvaluator.isTiledTopRight()) {
+ workspace.slotWindowQuickTileRight();
// M > B
- } else if (_IsMaximized()) {
- workspace.slotWindowQuickTileBottom()
- workspace.slotWindowQuickTileBottom()
- } else {
- workspace.slotWindowMinimize()
- }
-}
-
-var QuickTileLeft = function() {
- // T > TL
- if (_IsTiledTop()) {
- workspace.slotWindowQuickTileTopLeft()
+ } else if (tileEvaluator.isMaximized()) {
+ workspace.slotWindowMaximize();
+ } else {
+ workspace.slotWindowMinimize();
+ }
+};
+
+var QuickTileLeft = function () {
+ const tileEvaluator = _tileEvaluator();
+
+ // T > TL
+ if (tileEvaluator.isTiledTop()) {
+ workspace.slotWindowQuickTileTopLeft();
// B > BL
- } else if (_IsTiledBottom()) {
- workspace.slotWindowQuickTileBottomLeft()
+ } else if (tileEvaluator.isTiledBottom()) {
+ workspace.slotWindowQuickTileBottomLeft();
// TR > T
- } else if (_IsTiledTopRight()) {
- workspace.slotWindowQuickTileTop()
+ } else if (tileEvaluator.isTiledTopRight()) {
+ workspace.slotWindowQuickTileTop();
// BR > B
- } else if (_IsTiledBottomRight()) {
- workspace.slotWindowQuickTileBottom()
+ } else if (tileEvaluator.isTiledBottomRight()) {
+ workspace.slotWindowQuickTileBottom();
// M > L
- } else if (_IsMaximized()) {
- workspace.slotWindowQuickTileLeft()
- workspace.slotWindowQuickTileLeft()
+ } else if (tileEvaluator.isMaximized()) {
+ workspace.slotWindowQuickTileLeft();
// R > L, BL > L, TL > L
- } else {
- workspace.slotWindowQuickTileLeft()
- }
-}
+ } else {
+ workspace.slotWindowQuickTileLeft();
+ }
+};
+
+var QuickTileRight = function () {
+ const tileEvaluator = _tileEvaluator();
-var QuickTileRight = function() {
- // T > TR
- if (_IsTiledTop()) {
- workspace.slotWindowQuickTileTopRight()
+ // T > TR
+ if (tileEvaluator.isTiledTop()) {
+ workspace.slotWindowQuickTileTopRight();
// B > BR
- } else if (_IsTiledBottom()) {
- workspace.slotWindowQuickTileBottomRight()
+ } else if (tileEvaluator.isTiledBottom()) {
+ workspace.slotWindowQuickTileBottomRight();
// TL > T
- } else if (_IsTiledTopLeft()) {
- workspace.slotWindowQuickTileTop()
+ } else if (tileEvaluator.isTiledTopLeft()) {
+ workspace.slotWindowQuickTileTop();
// BL > B
- } else if (_IsTiledBottomLeft()) {
- workspace.slotWindowQuickTileBottom()
+ } else if (tileEvaluator.isTiledBottomLeft()) {
+ workspace.slotWindowQuickTileBottom();
// M > R
- } else if (_IsMaximized()) {
- workspace.slotWindowQuickTileRight()
- workspace.slotWindowQuickTileRight()
+ } else if (tileEvaluator.isMaximized()) {
+ workspace.slotWindowQuickTileRight();
// L > R, BR > R, TR > R
- } else {
- workspace.slotWindowQuickTileRight()
- }
-}
-
-
-var shortcutPrefix = "Quick Tile 2 "
-registerShortcut(shortcutPrefix + "Up", shortcutPrefix + "Up", "Meta+Up", QuickTileUp)
-registerShortcut(shortcutPrefix + "Down", shortcutPrefix + "Down", "Meta+Down", QuickTileDown)
-registerShortcut(shortcutPrefix + "Left", shortcutPrefix + "Left", "Meta+Left", QuickTileLeft)
-registerShortcut(shortcutPrefix + "Right", shortcutPrefix + "Right", "Meta+Right", QuickTileRight)
+ } else {
+ workspace.slotWindowQuickTileRight();
+ }
+};
+
+var shortcutPrefix = "Quick Tile 2 ";
+registerShortcut(
+ shortcutPrefix + "Up",
+ shortcutPrefix + "Up",
+ "Meta+Up",
+ QuickTileUp
+);
+registerShortcut(
+ shortcutPrefix + "Down",
+ shortcutPrefix + "Down",
+ "Meta+Down",
+ QuickTileDown
+);
+registerShortcut(
+ shortcutPrefix + "Left",
+ shortcutPrefix + "Left",
+ "Meta+Left",
+ QuickTileLeft
+);
+registerShortcut(
+ shortcutPrefix + "Right",
+ shortcutPrefix + "Right",
+ "Meta+Right",
+ QuickTileRight
+);
diff --git a/install.sh b/install.sh
deleted file mode 100644
index fa5378a..0000000
--- a/install.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-rm ./quick-tile-*
-zip -r quick-tile-2-v$(cat metadata.desktop | grep X-KDE-PluginInfo-Version= | awk -F'=' '{print $2}').kwinscript *
-rm -rf ~/.local/share/kwin/scripts/quick-tile-2*
-plasmapkg2 --type kwinscript -i quick-tile-2-v*.kwinscript
-qdbus org.kde.KWin /KWin reconfigure
-mkdir -p ~/.local/share/kservices5
-cp ~/.local/share/kwin/scripts/quick-tile-2/metadata.desktop ~/.local/share/kservices5/kwin-script-quick-tile-2.desktop
-kwin_x11 --replace >/dev/null 2>&1 &
diff --git a/metadata.desktop b/metadata.desktop
deleted file mode 100644
index 31ff905..0000000
--- a/metadata.desktop
+++ /dev/null
@@ -1,20 +0,0 @@
-[Desktop Entry]
-Name=Quick Tile 2
-Comment=Allows quick tiling support like the 2x2 Snap feature in Windows 10, but also allows windows to occupy top or bottom half of the screen. https://github.com/tsoernes/kwin-quick-tile-2 Forked from Quick Tiling - Windows 10 by Koen Hausmans (koen@hausmans.nl)
-Icon=preferences-system-windows-script-test
-
-Type=Service
-
-X-Plasma-API=javascript
-X-Plasma-MainScript=code/main.js
-
-X-KDE-PluginInfo-Author=Torstein Soernes
-X-KDE-PluginInfo-Email=t.soernes@gmail.com
-X-KDE-PluginInfo-Name=quick-tile-2
-X-KDE-PluginInfo-Version=0.1.0
-
-X-KDE-PluginInfo-Depends=
-X-KDE-PluginInfo-License=GPL
-X-KDE-ServiceTypes=KWin/Script
-X-KDE-PluginKeyword=quick-tile-2
-
diff --git a/metadata.json b/metadata.json
new file mode 100644
index 0000000..86880bf
--- /dev/null
+++ b/metadata.json
@@ -0,0 +1,28 @@
+{
+ "KPlugin": {
+ "Id": "com.github.tsoernes.kwin-quick-tile-2",
+
+ "Name": "Quick Tile 2",
+ "Description": "Allows quick tiling support like the 2x2 Snap feature in Windows 10, but also allows windows to occupy top or bottom half of the screen.",
+ "Version": "0.3.0",
+ "Website": "https://github.com/tsoernes/kwin-quick-tile-2/",
+
+ "Icon": "references-system-windows-script-test",
+ "License": "GPLv3",
+
+ "Authors": [
+ {
+ "Name": "Torstein Soernes",
+ "Email": "t.soernes@gmail.com"
+ },
+ {
+ "Name": "Andreas Schneider",
+ "Email": "aksdb@gmx.de"
+ }
+ ],
+ "EnabledByDefault": true
+ },
+ "X-Plasma-API": "javascript",
+ "X-Plasma-MainScript": "code/main.js",
+ "KPackageStructure": "KWin/Script"
+}