initial commit
This commit is contained in:
commit
06b84e5ba9
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Build artifacts
|
||||||
|
*.kwinscript
|
||||||
|
|
||||||
|
# Editor files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.kate-swp
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Node (if using build tools)
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
/**
|
||||||
|
* KWin Scratchpad — i3-like hide/show/cycle behavior.
|
||||||
|
*
|
||||||
|
* Two shortcuts:
|
||||||
|
* Meta+Shift+- : Move active window to scratchpad (hide it).
|
||||||
|
* Meta+- : Show/hide/cycle through scratchpad windows.
|
||||||
|
*
|
||||||
|
* Cycle behavior (Meta+-):
|
||||||
|
* - If a scratchpad window is visible: hide it.
|
||||||
|
* - If no scratchpad window is visible: show the next one.
|
||||||
|
* - Wraps around the list.
|
||||||
|
*
|
||||||
|
* A window leaves the scratchpad ONLY when:
|
||||||
|
* - It is closed.
|
||||||
|
* - It is explicitly moved to a desktop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// --- State ---
|
||||||
|
var scratchpad = []; // ordered list of windows in the scratchpad
|
||||||
|
var visibleWindow = null; // the currently-visible scratchpad window, or null
|
||||||
|
var nextIndex = 0; // which window to show on the next "show" press
|
||||||
|
|
||||||
|
// --- Helpers ---
|
||||||
|
|
||||||
|
function indexInScratchpad(win) {
|
||||||
|
for (var i = 0; i < scratchpad.length; i++) {
|
||||||
|
if (scratchpad[i] === win) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isScratchpadWindow(win) {
|
||||||
|
return indexInScratchpad(win) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeScratchpadWindow(win) {
|
||||||
|
var i = indexInScratchpad(win);
|
||||||
|
if (i < 0) return false;
|
||||||
|
|
||||||
|
scratchpad.splice(i, 1);
|
||||||
|
|
||||||
|
if (win === visibleWindow) {
|
||||||
|
visibleWindow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep nextIndex in bounds
|
||||||
|
if (scratchpad.length === 0) {
|
||||||
|
nextIndex = 0;
|
||||||
|
} else if (nextIndex >= scratchpad.length) {
|
||||||
|
nextIndex = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideWindow(win) {
|
||||||
|
win.minimized = true;
|
||||||
|
win.skipTaskbar = true;
|
||||||
|
win.skipPager = true;
|
||||||
|
win.skipSwitcher = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWindow(win) {
|
||||||
|
win.desktops = [workspace.currentDesktop];
|
||||||
|
win.minimized = false;
|
||||||
|
win.skipTaskbar = true;
|
||||||
|
win.skipPager = true;
|
||||||
|
win.skipSwitcher = true;
|
||||||
|
workspace.activeWindow = win;
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreWindow(win) {
|
||||||
|
win.minimized = false;
|
||||||
|
win.skipTaskbar = false;
|
||||||
|
win.skipPager = false;
|
||||||
|
win.skipSwitcher = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Shortcut 1: Add to scratchpad (Meta+Shift+-) ---
|
||||||
|
|
||||||
|
function scratchpadAdd() {
|
||||||
|
var active = workspace.activeWindow;
|
||||||
|
if (!active) return;
|
||||||
|
if (active.desktopWindow || active.dock || active.specialWindow) return;
|
||||||
|
if (isScratchpadWindow(active)) return;
|
||||||
|
|
||||||
|
scratchpad.push(active);
|
||||||
|
hideWindow(active);
|
||||||
|
print("Scratchpad: added — " + active.caption + " (" + scratchpad.length + " total)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Shortcut 2: Show/hide/cycle (Meta+-) ---
|
||||||
|
|
||||||
|
function scratchpadCycle() {
|
||||||
|
if (scratchpad.length === 0) return;
|
||||||
|
|
||||||
|
// If a scratchpad window is currently visible — hide it. Full stop.
|
||||||
|
if (visibleWindow !== null) {
|
||||||
|
hideWindow(visibleWindow);
|
||||||
|
// Advance nextIndex past the one we just hid
|
||||||
|
var idx = indexInScratchpad(visibleWindow);
|
||||||
|
if (idx >= 0) {
|
||||||
|
nextIndex = (idx + 1) % scratchpad.length;
|
||||||
|
}
|
||||||
|
visibleWindow = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No scratchpad window is visible — show the next one.
|
||||||
|
if (nextIndex >= scratchpad.length) {
|
||||||
|
nextIndex = 0;
|
||||||
|
}
|
||||||
|
visibleWindow = scratchpad[nextIndex];
|
||||||
|
showWindow(visibleWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Track window closure ---
|
||||||
|
|
||||||
|
workspace.windowRemoved.connect(function (win) {
|
||||||
|
removeScratchpadWindow(win);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Track desktop changes (window explicitly moved to a desktop) ---
|
||||||
|
|
||||||
|
function watchDesktopChange(win) {
|
||||||
|
win.desktopsChanged.connect(function () {
|
||||||
|
if (!isScratchpadWindow(win)) return;
|
||||||
|
|
||||||
|
// If it's the visible one and not minimized, this is likely our
|
||||||
|
// own showWindow() call — ignore.
|
||||||
|
if (win === visibleWindow && !win.minimized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User moved it to a desktop — release from scratchpad.
|
||||||
|
removeScratchpadWindow(win);
|
||||||
|
restoreWindow(win);
|
||||||
|
print("Scratchpad: window released to desktop — " + win.caption);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var clients = workspace.stackingOrder;
|
||||||
|
for (var i = 0; i < clients.length; i++) {
|
||||||
|
watchDesktopChange(clients[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace.windowAdded.connect(function (win) {
|
||||||
|
watchDesktopChange(win);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Register shortcuts ---
|
||||||
|
|
||||||
|
registerShortcut(
|
||||||
|
"ScratchpadAdd",
|
||||||
|
"Move Window to Scratchpad",
|
||||||
|
"Meta+Shift+-",
|
||||||
|
scratchpadAdd
|
||||||
|
);
|
||||||
|
|
||||||
|
registerShortcut(
|
||||||
|
"ScratchpadCycle",
|
||||||
|
"Scratchpad Show/Hide/Cycle",
|
||||||
|
"Meta+-",
|
||||||
|
scratchpadCycle
|
||||||
|
);
|
||||||
|
|
||||||
|
print("KWin Scratchpad loaded");
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||||
|
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||||
|
<kcfgfile name=""/>
|
||||||
|
<group name="General">
|
||||||
|
<entry name="shortcut" type="String">
|
||||||
|
<label>Keyboard shortcut for scratchpad toggle</label>
|
||||||
|
<default>Meta+-</default>
|
||||||
|
</entry>
|
||||||
|
</group>
|
||||||
|
</kcfg>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Install kwin-scratchpad KWin script
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PACKAGE_DIR="$SCRIPT_DIR/"
|
||||||
|
|
||||||
|
echo "Installing kwin-scratchpad..."
|
||||||
|
|
||||||
|
# Remove old version if present
|
||||||
|
kpackagetool6 --type=KWin/Script -r kwin-scratchpad 2>/dev/null || true
|
||||||
|
|
||||||
|
# Install
|
||||||
|
kpackagetool6 --type=KWin/Script -i "$PACKAGE_DIR"
|
||||||
|
|
||||||
|
# Enable the script
|
||||||
|
kwriteconfig6 --file kwinrc --group Plugins --key kwin-scratchpadEnabled true
|
||||||
|
|
||||||
|
# Reload KWin
|
||||||
|
qdbus6 org.kde.KWin /KWin reconfigure
|
||||||
|
|
||||||
|
echo "Done. Shortcut: Meta+- (configurable in System Settings > Shortcuts)"
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"KPlugin": {
|
||||||
|
"Name": "Scratchpad",
|
||||||
|
"Description": "i3-like scratchpad: hide the active window, then cycle through hidden scratchpad windows on subsequent presses",
|
||||||
|
"Icon": "preferences-system-windows",
|
||||||
|
"Authors": [
|
||||||
|
{
|
||||||
|
"Name": "lkn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Id": "kwin-scratchpad",
|
||||||
|
"Version": "1.0",
|
||||||
|
"License": "GPLv3"
|
||||||
|
},
|
||||||
|
"X-Plasma-API": "javascript",
|
||||||
|
"X-Plasma-MainScript": "code/main.js",
|
||||||
|
"KPackageStructure": "KWin/Script"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue