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