feat: add dynamic preview panel resizing and individual window instance close button
This commit is contained in:
parent
7e815d4a51
commit
f40fc29e3f
@ -495,10 +495,14 @@ Item {
|
|||||||
|
|
||||||
GlassPanel {
|
GlassPanel {
|
||||||
id: previewGlass
|
id: previewGlass
|
||||||
implicitWidth: previewMainCol.implicitWidth + 20
|
implicitWidth: previewMainCol.implicitWidth + 24
|
||||||
implicitHeight: previewMainCol.implicitHeight + 16
|
implicitHeight: previewMainCol.implicitHeight + 16
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
NumberAnimation { duration: 180; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
opacity: dockWindowPreview.animProgress
|
opacity: dockWindowPreview.animProgress
|
||||||
scale: 0.90 + 0.10 * dockWindowPreview.animProgress
|
scale: 0.90 + 0.10 * dockWindowPreview.animProgress
|
||||||
transformOrigin: Item.Bottom
|
transformOrigin: Item.Bottom
|
||||||
@ -634,7 +638,10 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
TaskService.closeApp(modelData.appId)
|
TaskService.closeSpecificWindow(modelData)
|
||||||
|
let rem = root.previewWindowInstances ? root.previewWindowInstances.filter(w => w.id !== modelData.id) : []
|
||||||
|
root.previewWindowInstances = rem
|
||||||
|
if (!rem || rem.length === 0) {
|
||||||
previewPopIn.running = false
|
previewPopIn.running = false
|
||||||
previewPopOut.restart()
|
previewPopOut.restart()
|
||||||
}
|
}
|
||||||
@ -642,6 +649,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Miniature Glass Window Preview Container
|
// Miniature Glass Window Preview Container
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
@ -169,6 +169,16 @@ Item {
|
|||||||
proc.running = true
|
proc.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeSpecificWindow(winObj) {
|
||||||
|
if (!winObj) return;
|
||||||
|
let winId = (winObj.id || "").toString().trim()
|
||||||
|
let query = (winObj.caption || winObj.appId || "").toLowerCase().trim()
|
||||||
|
|
||||||
|
proc.running = false
|
||||||
|
proc.command = ["python3", Quickshell.env("HOME") + "/.config/quickshell/services/python/kwin_close.py", winId, query]
|
||||||
|
proc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
function focusApp(appId, cmd, iconX, iconY) {
|
function focusApp(appId, cmd, iconX, iconY) {
|
||||||
if (!appId) return;
|
if (!appId) return;
|
||||||
let lower = appId.toLowerCase().trim()
|
let lower = appId.toLowerCase().trim()
|
||||||
|
|||||||
30
quickshell/services/js/kwin_close.js
Normal file
30
quickshell/services/js/kwin_close.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// KWin JavaScript Script: Gracefully Close Specific Window Instance
|
||||||
|
var targetId = "%WIN_ID%".trim();
|
||||||
|
var targetQuery = "%TARGET_QUERY%".toLowerCase().trim();
|
||||||
|
|
||||||
|
if (targetId || targetQuery) {
|
||||||
|
var windows = workspace.windowList();
|
||||||
|
for (var i = 0; i < windows.length; i++) {
|
||||||
|
var win = windows[i];
|
||||||
|
var id = String(win.internalId || win.windowId || "");
|
||||||
|
var cls = (win.desktopFileName || win.resourceClass || win.resourceName || "").toLowerCase().trim();
|
||||||
|
var caption = (win.caption || "").toLowerCase().trim();
|
||||||
|
|
||||||
|
var matches = false;
|
||||||
|
if (targetId && id && (id === targetId || id.indexOf(targetId) !== -1)) {
|
||||||
|
matches = true;
|
||||||
|
}
|
||||||
|
if (!matches && targetQuery) {
|
||||||
|
if (caption && caption.indexOf(targetQuery) !== -1) {
|
||||||
|
matches = true;
|
||||||
|
} else if (cls && cls.indexOf(targetQuery) !== -1) {
|
||||||
|
matches = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
win.closeWindow();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
quickshell/services/python/kwin_close.py
Normal file
36
quickshell/services/python/kwin_close.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
JS_TEMPLATE_PATH = os.path.expanduser('~/.config/quickshell/services/js/kwin_close.js')
|
||||||
|
|
||||||
|
def close_window(win_id="", target_query=""):
|
||||||
|
try:
|
||||||
|
with open(JS_TEMPLATE_PATH, 'r', encoding='utf-8') as f:
|
||||||
|
template = f.read()
|
||||||
|
|
||||||
|
script = template.replace('%WIN_ID%', win_id).replace('%TARGET_QUERY%', target_query)
|
||||||
|
|
||||||
|
target_js = '/tmp/kwin_close.js'
|
||||||
|
with open(target_js, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(script)
|
||||||
|
|
||||||
|
# Unload previous script instance to prevent KWin memory leaks
|
||||||
|
subprocess.run(['busctl', '--user', 'call', 'org.kde.KWin', '/Scripting', 'org.kde.kwin.Scripting', 'unloadScript', 's', target_js], capture_output=True)
|
||||||
|
|
||||||
|
res = subprocess.check_output(
|
||||||
|
['busctl', '--user', 'call', 'org.kde.KWin', '/Scripting', 'org.kde.kwin.Scripting', 'loadScript', 's', target_js],
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
sid = res.strip().split()[-1]
|
||||||
|
subprocess.run(['busctl', '--user', 'call', 'org.kde.KWin', f'/Scripting/Script{sid}', 'org.kde.kwin.Script', 'run'], capture_output=True)
|
||||||
|
subprocess.run(['busctl', '--user', 'call', 'org.kde.KWin', f'/Scripting/Script{sid}', 'org.kde.kwin.Script', 'stop'], capture_output=True)
|
||||||
|
subprocess.run(['busctl', '--user', 'call', 'org.kde.KWin', '/Scripting', 'org.kde.kwin.Scripting', 'unloadScript', 's', target_js], capture_output=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
win_id = sys.argv[1] if len(sys.argv) >= 2 else ""
|
||||||
|
target_query = sys.argv[2] if len(sys.argv) >= 3 else ""
|
||||||
|
close_window(win_id, target_query)
|
||||||
Loading…
Reference in New Issue
Block a user