From 6d8487e7d6b0f6609eead3c6b2249be2bc8525ba Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 19 Nov 2023 21:36:59 -0900 Subject: [PATCH 01/28] Start splitting for KDE 5/6 --- .vscode/settings.json | 8 ++ install.sh | 64 +++++++++++- {contents => kde5/contents}/code/main.js | 0 metadata.json => kde5/metadata.json | 0 kde6/contents/code/main.js | 124 +++++++++++++++++++++++ kde6/metadata.json | 24 +++++ 6 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 .vscode/settings.json rename {contents => kde5/contents}/code/main.js (100%) rename metadata.json => kde5/metadata.json (100%) create mode 100644 kde6/contents/code/main.js create mode 100644 kde6/metadata.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f3e0f5d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "settings": { + "workbench.colorCustomizations": { + "titleBar.activeBackground": "#cc00ff23", + "activityBar.background": "#cc00ff23" + } + } +} \ No newline at end of file diff --git a/install.sh b/install.sh index 460763c..3458dd8 100755 --- a/install.sh +++ b/install.sh @@ -1,5 +1,59 @@ -#!/bin/bash -name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') -kpackagetool5 --type=KWin/Script --install . || kpackagetool5 --type=KWin/Script --upgrade . -kwriteconfig5 --file kwinrc --group Plugins --key "$name"Enabled true -qdbus org.kde.KWin /KWin reconfigure +#!/usr/bin/env bash + + +# This is a script to install the "Application Switcher" KWin script + + +exit_w_error() { + local msg="$1" + echo -e "\n(EE) ERROR: ${msg} Exiting...\n" + exit 1 +} + +script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') + +if command -v "kpackagetool5"; then + kpackagetool5 --type=KWin/Script --install . || kpackagetool5 --type=KWin/Script --upgrade . +else + exit_w_error "The 'kpackagetool5' command was not found." +fi + +if command -v "kwriteconfig5"; then + kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true +else + exit_w_error "The 'kwriteconfig5' command was not found." +fi + +# We need to gracefully cascade through common D-Bus utils to find one that is available. + +# Array of command names of common D-Bus utilities +dbus_commands=("qdbus" "gdbus" "dbus-send") + +# Function to reconfigure KWin using qdbus +reconfigure_with_qdbus() { + qdbus org.kde.KWin /KWin reconfigure +} + +# Function to reconfigure KWin using gdbus +reconfigure_with_gdbus() { + gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure +} + +# Function to reconfigure KWin using dbus-send +reconfigure_with_dbus_send() { + dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure +} + +# Iterate through the dbus_commands array +for cmd in "${dbus_commands[@]}"; do + if command -v "$cmd" &> /dev/null; then + # Call the corresponding function based on the command + case "$cmd" in + qdbus) reconfigure_with_qdbus ;; + gdbus) reconfigure_with_gdbus ;; + dbus-send) reconfigure_with_dbus_send ;; + esac + # Break out of the loop once a command is found and executed + break + fi +done diff --git a/contents/code/main.js b/kde5/contents/code/main.js similarity index 100% rename from contents/code/main.js rename to kde5/contents/code/main.js diff --git a/metadata.json b/kde5/metadata.json similarity index 100% rename from metadata.json rename to kde5/metadata.json diff --git a/kde6/contents/code/main.js b/kde6/contents/code/main.js new file mode 100644 index 0000000..4567e70 --- /dev/null +++ b/kde6/contents/code/main.js @@ -0,0 +1,124 @@ +/* +KWin Script Application Switcher +(C) 2022 Natalie Clarius +GNU General Public License v3.0 +*/ + +/////////////////////// +// initialization +/////////////////////// + +const debugMode = readConfig("debugMode", true); +function debug(...args) { + if (debugMode) { console.debug("applicationswitcher:", ...args); } +} +debug("initializing"); + + +/////////////////////// +// special applications to ignore +/////////////////////// + +const ignoredApps = ["plasmashell", "org.kde.plasmashell", // desktop shell + "krunner", "org.kde.krunner", // KRunner + "kwin_wayland", // lock screen + "org.kde.ksmserver-logout-greeter", // logout screen + "ksplashqml" // login splash screen + ]; + + +/////////////////////// +// get application a window belongs to +/////////////////////// + +// "dolphin" +function getApp(current) { + if (!current) return ""; + return String(current.resourceClass); +} + + +/////////////////////// +// keep track of active application (to check whether app has been switched) +/////////////////////// + +// "dolphin" +var prevActiveApp = "" + +// set previously active application for initially active window +setPrevActiveApp(workspace.activeWindow); + +// set previously active application for recently activated window +function setPrevActiveApp(current) { + if (!current) return; + prevActiveApp = getApp(current); +} + +// get previously active application +function getPrevActiveApp() { + return prevActiveApp; +} + + +/////////////////////// +// keep track of windows belonging to same application in order of activation +/////////////////////// + +// {"dolphin": [oldest window, ..., most recent window], "konsole": ...} +var appGroups = {}; + +// compute app groups for initially present windows +workspace.windowList().forEach(window => updateAppGroups(window)); + +// update app groups with given window +function updateAppGroups(current) { + if (!current) return; + let app = getApp(current); + if (!appGroups[app]) appGroups[app] = []; + appGroups[app] = appGroups[app].filter(window => window && + window != current); + appGroups[app].push(current); + debug("updating app group", appGroups[app].map(window => window.caption)); +} + +// return other visible windows of same application as given window +function getAppGroup(current) { + if (!current) return; + let appGroup = appGroups[getApp(current)].filter(window => window && + !window.minimized && + (window.x11DesktopIds.includes(workspace.currentDesktop) || window.x11DesktopIds.length == 0) && + (window.activities.includes(workspace.currentActivity) || window.activities.length == 0)); + debug("getting app group", appGroup.map(window => window.caption)); + return appGroup; +} + + +/////////////////////// +// main +/////////////////////// + +// when window is activated, auto-raise other windows of the same applicaiton +workspace.windowActivated.connect(active => { + if (!active) return; + debug("---------"); + debug("activated", active.caption); + debug("app", getApp(active)); + // abort if application is ignored + if (ignoredApps.includes(getApp(active))) { + debug("ignored"); + return; + } + updateAppGroups(active); + + // if application was switched + debug("previous app", getPrevActiveApp()); + if (getApp(active) != getPrevActiveApp()) { + debug("app switched"); + setPrevActiveApp(active); + // auto-raise other windows of same application + for (let window of getAppGroup(active)) { + debug("auto-raising", window.caption); + workspace.activeWindow = window; + } + } +}); diff --git a/kde6/metadata.json b/kde6/metadata.json new file mode 100644 index 0000000..f4f10a4 --- /dev/null +++ b/kde6/metadata.json @@ -0,0 +1,24 @@ +{ + "KPackageStructure": "KWin/Script", + "KPlugin": { + "Authors": [ + { + "Email": "natalie_clarius@yahoo.de", + "Name": "Natalie Clarius" + } + ], + "Description": "Collectively raises all windows of the same application when switching tasks", + "Icon": "preferences-system-windows", + "Id": "applicationswitcher", + "License": "GPLv3.0", + "Name": "Application Switcher", + "ServiceTypes": [ + "KWin/Script", + "KCModule" + ], + "Version": "1.6", + "Website": "" + }, + "X-Plasma-API": "javascript", + "X-Plasma-MainScript": "code/main.js" +} From 279f4d7e3bdf4c209a0c77acad42971b26ca4b3d Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 19 Nov 2023 21:50:42 -0900 Subject: [PATCH 02/28] Merge grouping fix branch changes --- kde5/contents/code/main.js | 34 +++++++++++++++++++++++++--------- kde6/contents/code/main.js | 34 +++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/kde5/contents/code/main.js b/kde5/contents/code/main.js index 5245f68..fada7ea 100644 --- a/kde5/contents/code/main.js +++ b/kde5/contents/code/main.js @@ -33,7 +33,7 @@ const ignoredApps = ["plasmashell", "org.kde.plasmashell", // desktop shell // "dolphin" function getApp(current) { - if (!current) return ""; + if (!current || typeof current.resourceClass !== 'string') return ""; return String(current.resourceClass); } @@ -78,17 +78,31 @@ function updateAppGroups(current) { appGroups[app] = appGroups[app].filter(window => window && window != current); appGroups[app].push(current); - debug("updating app group", appGroups[app].map(window => window.caption)); + debug("updating app group", appGroups[app].map(window => + window && window.caption ? window.caption : "undefined window" + )); } // return other visible windows of same application as given window function getAppGroup(current) { if (!current) return; - let appGroup = appGroups[getApp(current)].filter(window => window && + + let appGroup = appGroups[getApp(current)].filter(window => + window && !window.minimized && - (window.x11DesktopIds.includes(workspace.currentDesktop) || window.x11DesktopIds.length == 0) && - (window.activities.includes(workspace.currentActivity) || window.activities.length == 0)); - debug("getting app group", appGroup.map(window => window.caption)); + ( + (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || + (window.x11DesktopIds && window.x11DesktopIds.length === 0) + ) && + ( + (window.activities && window.activities.includes(workspace.currentActivity)) || + (window.activities && window.activities.length === 0) + ) + ); + + debug("getting app group", appGroup.map(window => + window && window.caption ? window.caption : "undefined window" + )); return appGroup; } @@ -97,7 +111,7 @@ function getAppGroup(current) { // main /////////////////////// -// when client is activated, auto-raise other windows of the same applicaiton +// when client is activated, auto-raise other windows of the same application workspace.clientActivated.connect(active => { if (!active) return; debug("---------"); @@ -117,8 +131,10 @@ workspace.clientActivated.connect(active => { setPrevActiveApp(active); // auto-raise other windows of same application for (let window of getAppGroup(active)) { - debug("auto-raising", window.caption); - workspace.activeClient = window; + if (window) { + debug("auto-raising", window.caption); + workspace.activeClient = window; + } } } }); diff --git a/kde6/contents/code/main.js b/kde6/contents/code/main.js index 4567e70..05d835a 100644 --- a/kde6/contents/code/main.js +++ b/kde6/contents/code/main.js @@ -33,7 +33,7 @@ const ignoredApps = ["plasmashell", "org.kde.plasmashell", // desktop shell // "dolphin" function getApp(current) { - if (!current) return ""; + if (!current || typeof current.resourceClass !== 'string') return ""; return String(current.resourceClass); } @@ -78,17 +78,31 @@ function updateAppGroups(current) { appGroups[app] = appGroups[app].filter(window => window && window != current); appGroups[app].push(current); - debug("updating app group", appGroups[app].map(window => window.caption)); + debug("updating app group", appGroups[app].map(window => + window && window.caption ? window.caption : "undefined window" + )); } // return other visible windows of same application as given window function getAppGroup(current) { if (!current) return; - let appGroup = appGroups[getApp(current)].filter(window => window && + + let appGroup = appGroups[getApp(current)].filter(window => + window && !window.minimized && - (window.x11DesktopIds.includes(workspace.currentDesktop) || window.x11DesktopIds.length == 0) && - (window.activities.includes(workspace.currentActivity) || window.activities.length == 0)); - debug("getting app group", appGroup.map(window => window.caption)); + ( + (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || + (window.x11DesktopIds && window.x11DesktopIds.length === 0) + ) && + ( + (window.activities && window.activities.includes(workspace.currentActivity)) || + (window.activities && window.activities.length === 0) + ) + ); + + debug("getting app group", appGroup.map(window => + window && window.caption ? window.caption : "undefined window" + )); return appGroup; } @@ -97,7 +111,7 @@ function getAppGroup(current) { // main /////////////////////// -// when window is activated, auto-raise other windows of the same applicaiton +// when window is activated, auto-raise other windows of the same application workspace.windowActivated.connect(active => { if (!active) return; debug("---------"); @@ -117,8 +131,10 @@ workspace.windowActivated.connect(active => { setPrevActiveApp(active); // auto-raise other windows of same application for (let window of getAppGroup(active)) { - debug("auto-raising", window.caption); - workspace.activeWindow = window; + if (window) { + debug("auto-raising", window.caption); + workspace.activeWindow = window; + } } } }); From 416c5ea4fafed7edc28ba78cb43324cc2ebdde20 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Mon, 20 Nov 2023 02:55:22 -0900 Subject: [PATCH 03/28] Merge code for KDE 5 and 6 together --- contents/code/main.js | 162 ++++++++++++++++++++++++++++++++++++++++++ install.sh | 77 ++++++++++++++------ kde5/metadata.json | 1 + metadata.json | 24 +++++++ uninstall.sh | 80 ++++++++++++++++++++- 5 files changed, 320 insertions(+), 24 deletions(-) create mode 100644 contents/code/main.js create mode 100644 metadata.json diff --git a/contents/code/main.js b/contents/code/main.js new file mode 100644 index 0000000..acd7a5f --- /dev/null +++ b/contents/code/main.js @@ -0,0 +1,162 @@ +/* +KWin Script Application Switcher +(C) 2022 Natalie Clarius +GNU General Public License v3.0 +*/ + +/////////////////////// +// initialization +/////////////////////// + +const debugMode = readConfig("debugMode", true); +function debug(...args) { + if (debugMode) { console.debug("applicationswitcher:", ...args); } +} +debug("initializing"); + +// Detect KDE version +const isKDE6 = typeof workspace.windowList === 'function'; + +let activeWindow; +let windowList; +let connectWindowActivated; +let setActiveWindow; + +// Set up aliases to abstract away the API differences between KDE 5 and KDE 6 +if (isKDE6) { + activeWindow = () => workspace.activeWindow; + windowList = () => workspace.windowList(); + connectWindowActivated = (handler) => workspace.windowActivated.connect(handler); + setActiveWindow = (window) => { workspace.activeWindow = window; }; +} else { + activeWindow = () => workspace.activeClient; + windowList = () => workspace.clientList(); + connectWindowActivated = (handler) => workspace.clientActivated.connect(handler); + setActiveWindow = (window) => { workspace.activeClient = window; }; +} + +/////////////////////// +// special applications to ignore +/////////////////////// + +const ignoredApps = ["plasmashell", "org.kde.plasmashell", // desktop shell + "krunner", "org.kde.krunner", // KRunner + "kwin_wayland", // lock screen + "org.kde.ksmserver-logout-greeter", // logout screen + "ksplashqml" // login splash screen + ]; + + +/////////////////////// +// get application a window belongs to +/////////////////////// + +// "dolphin" +function getApp(current) { + if (!current || typeof current.resourceClass !== 'string') return ""; + return String(current.resourceClass); +} + + +/////////////////////// +// keep track of active application (to check whether app has been switched) +/////////////////////// + +// "dolphin" +var prevActiveApp = "" + +// set previously active application for initially active window +setPrevActiveApp(activeWindow()) + +// set previously active application for recently activated window +function setPrevActiveApp(current) { + if (!current) return; + prevActiveApp = getApp(current); +} + +// get previously active application +function getPrevActiveApp() { + return prevActiveApp; +} + + +/////////////////////// +// keep track of windows belonging to same application in order of activation +/////////////////////// + +// {"dolphin": [oldest window, ..., most recent window], "konsole": ...} +var appGroups = {}; + +// compute app groups for initially present windows +windowList().forEach(window => updateAppGroups(window)); + +// update app groups with given window +function updateAppGroups(current) { + if (!current) return; + let app = getApp(current); + if (!appGroups[app]) appGroups[app] = []; + appGroups[app] = appGroups[app].filter(window => window && + window != current); + appGroups[app].push(current); + debug("updating app group", appGroups[app].map(window => + window && window.caption ? window.caption : "undefined window" + )); +} + +// return other visible windows of same application as given window +function getAppGroup(current) { + if (!current) return; + + let appGroup = appGroups[getApp(current)].filter(window => + window && + !window.minimized && + ( + (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || + (window.x11DesktopIds && window.x11DesktopIds.length === 0) + ) && + ( + (window.activities && window.activities.includes(workspace.currentActivity)) || + (window.activities && window.activities.length === 0) + ) + ); + + debug("getting app group", appGroup.map(window => + window && window.caption ? window.caption : "undefined window" + )); + return appGroup; +} + + +/////////////////////// +// main +/////////////////////// + +// when client is activated, auto-raise other windows of the same application +function onWindowActivated(active) { + if (!active) return; + debug("---------"); + debug("activated", active.caption); + debug("app", getApp(active)); + // abort if application is ignored + if (ignoredApps.includes(getApp(active))) { + debug("ignored"); + return; + } + updateAppGroups(active); + + // if application was switched + debug("previous app", getPrevActiveApp()); + if (getApp(active) != getPrevActiveApp()) { + debug("app switched"); + setPrevActiveApp(active); + // auto-raise other windows of same application + for (let window of getAppGroup(active)) { + if (window) { + debug("auto-raising", window.caption); + setActiveWindow(window); + } + } + } +} + +connectWindowActivated(onWindowActivated); diff --git a/install.sh b/install.sh index 3458dd8..ab3d723 100755 --- a/install.sh +++ b/install.sh @@ -3,57 +3,92 @@ # This is a script to install the "Application Switcher" KWin script - exit_w_error() { local msg="$1" echo -e "\n(EE) ERROR: ${msg} Exiting...\n" exit 1 } -script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') +install_w_kpackagetool6() { + echo "Installing KWin script: '${script_name}'" + kpackagetool6 --type="${script_type}" --install "${script_path}" || \ + kpackagetool6 --type="${script_type}" --upgrade "${script_path}" +} -if command -v "kpackagetool5"; then - kpackagetool5 --type=KWin/Script --install . || kpackagetool5 --type=KWin/Script --upgrade . -else - exit_w_error "The 'kpackagetool5' command was not found." -fi +install_w_kpackagetool5() { + echo "Installing KWin script: '${script_name}'" + kpackagetool5 --type="${script_type}" --install "${script_path}" || \ + kpackagetool5 --type="${script_type}" --upgrade "${script_path}" +} -if command -v "kwriteconfig5"; then - kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true +KDE_ver=${KDE_SESSION_VERSION:-0} +script_type="KWin/Script" +script_path="." +script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') + +if [[ ${KDE_ver} -eq 6 ]]; then + if command -v kpackagetool6; then + if install_w_kpackagetool6; then + if command -v kwriteconfig6; then + kwriteconfig6 --file kwinrc --group Plugins --key "$script_name"Enabled true + else + exit_w_error "The 'kwriteconfig6' command was not found. Cannot enable KWin script." + fi + else + exit_w_error "Problem installing '${script_name}' with kpackagetool6." + fi + else + echo "The 'kpackagetool6' command was not found. Cannot install KWin script." + fi +elif [[ ${KDE_ver} -eq 5 ]]; then + if command -v kpackagetool5; then + if install_w_kpackagetool5; then + if command -v kwriteconfig5; then + kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true + else + exit_w_error "The 'kwriteconfig5' command was not found. Cannot enable KWin script." + fi + else + exit_w_error "Problem installing '${script_name}' with kpackagetool5." + fi + else + exit_w_error "The 'kpackagetool5' command was not found." + fi else - exit_w_error "The 'kwriteconfig5' command was not found." + exit_w_error "KDE version not recognized. Cannot install the KWin script." fi -# We need to gracefully cascade through common D-Bus utils to find one that is available. +# We need to gracefully cascade through common D-Bus utils to +# find one that is available to use for the KWin reconfigure +# command. Sometimes 'qdbus' is not available. # Array of command names of common D-Bus utilities dbus_commands=("qdbus" "gdbus" "dbus-send") -# Function to reconfigure KWin using qdbus -reconfigure_with_qdbus() { +reconfigure_w_qdbus() { qdbus org.kde.KWin /KWin reconfigure } -# Function to reconfigure KWin using gdbus -reconfigure_with_gdbus() { +reconfigure_w_gdbus() { gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure } -# Function to reconfigure KWin using dbus-send -reconfigure_with_dbus_send() { +reconfigure_w_dbus_send() { dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure } # Iterate through the dbus_commands array for cmd in "${dbus_commands[@]}"; do - if command -v "$cmd" &> /dev/null; then + if command -v "${cmd}" &> /dev/null; then # Call the corresponding function based on the command case "$cmd" in - qdbus) reconfigure_with_qdbus ;; - gdbus) reconfigure_with_gdbus ;; - dbus-send) reconfigure_with_dbus_send ;; + qdbus) reconfigure_w_qdbus ;; + gdbus) reconfigure_w_gdbus ;; + dbus-send) reconfigure_w_dbus_send ;; esac # Break out of the loop once a command is found and executed break fi done + +echo "Finished installing KWin script: '${script_name}'" diff --git a/kde5/metadata.json b/kde5/metadata.json index e72013d..f4f10a4 100644 --- a/kde5/metadata.json +++ b/kde5/metadata.json @@ -1,4 +1,5 @@ { + "KPackageStructure": "KWin/Script", "KPlugin": { "Authors": [ { diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..fe6fad5 --- /dev/null +++ b/metadata.json @@ -0,0 +1,24 @@ +{ + "KPackageStructure": "KWin/Script", + "KPlugin": { + "Authors": [ + { + "Email": "natalie_clarius@yahoo.de", + "Name": "Natalie Clarius" + } + ], + "Description": "Collectively raises all windows of the same application when switching tasks", + "Icon": "preferences-system-windows", + "Id": "applicationswitcher", + "License": "GPLv3.0", + "Name": "Application Switcher", + "ServiceTypes": [ + "KWin/Script", + "KCModule" + ], + "Version": "1.7", + "Website": "" + }, + "X-Plasma-API": "javascript", + "X-Plasma-MainScript": "code/main.js" +} diff --git a/uninstall.sh b/uninstall.sh index 97db65b..75b0c63 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,3 +1,77 @@ -#!/bin/bash -kpackagetool5 --type=KWin/Script --remove . -qdbus org.kde.KWin /KWin reconfigure +#!/usr/bin/env bash + + +# This is a script to remove the "Application Switcher" KWin script + +exit_w_error() { + local msg="$1" + echo -e "\n(EE) ERROR: ${msg} Exiting...\n" + exit 1 +} + +remove_w_kpackagetool6() { + if command -v kpackagetool6; then + echo "Removing 'Application Switcher' KWin script." + kpackagetool6 --type=KWin/Script --remove . + else + exit_w_error "The 'kpackagetool6' command is missing. Cannot remove KWin script." + fi +} + +remove_w_kpackagetool5() { + if command -v kpackagetool5; then + echo "Removing 'Application Switcher' KWin script." + kpackagetool5 --type=KWin/Script --remove . + else + exit_w_error "The 'kpackagetool5' command is missing. Cannot remove KWin script." + fi +} + +KDE_ver=${KDE_SESSION_VERSION:-0} + + +if [[ $KDE_ver -eq 6 ]]; then + if remove_w_kpackagetool6; then + echo "KWin script removed." + fi +elif [[ ${KDE_ver} -eq 5 ]]; then + if remove_w_kpackagetool5; then + echo "KWin script removed." + fi +else + exit_w_error "KDE version not recognized. Cannot remove KWin script." +fi + + +# We need to gracefully cascade through common D-Bus utils to +# find one that is available to use for the KWin reconfigure +# command. Sometimes 'qdbus' is not available. + +# Array of command names of common D-Bus utilities +dbus_commands=("qdbus" "gdbus" "dbus-send") + +reconfigure_w_qdbus() { + qdbus org.kde.KWin /KWin reconfigure +} + +reconfigure_w_gdbus() { + gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure +} + +reconfigure_w_dbus_send() { + dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure +} + +# Iterate through the dbus_commands array +for cmd in "${dbus_commands[@]}"; do + if command -v "${cmd}" &> /dev/null; then + # Call the corresponding function based on the command + case "$cmd" in + qdbus) reconfigure_w_qdbus ;; + gdbus) reconfigure_w_gdbus ;; + dbus-send) reconfigure_w_dbus_send ;; + esac + # Break out of the loop once a command is found and executed + break + fi +done From 986bab481f9be94a9f0feb5ee41e86b39190cad5 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Mon, 20 Nov 2023 03:01:01 -0900 Subject: [PATCH 04/28] Supress output from command checks --- install.sh | 8 ++++---- uninstall.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index ab3d723..ff72267 100755 --- a/install.sh +++ b/install.sh @@ -27,9 +27,9 @@ script_path="." script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') if [[ ${KDE_ver} -eq 6 ]]; then - if command -v kpackagetool6; then + if command -v kpackagetool6 &> /dev/null; then if install_w_kpackagetool6; then - if command -v kwriteconfig6; then + if command -v kwriteconfig6 &> /dev/null; then kwriteconfig6 --file kwinrc --group Plugins --key "$script_name"Enabled true else exit_w_error "The 'kwriteconfig6' command was not found. Cannot enable KWin script." @@ -41,9 +41,9 @@ if [[ ${KDE_ver} -eq 6 ]]; then echo "The 'kpackagetool6' command was not found. Cannot install KWin script." fi elif [[ ${KDE_ver} -eq 5 ]]; then - if command -v kpackagetool5; then + if command -v kpackagetool5 &> /dev/null; then if install_w_kpackagetool5; then - if command -v kwriteconfig5; then + if command -v kwriteconfig5 &> /dev/null; then kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true else exit_w_error "The 'kwriteconfig5' command was not found. Cannot enable KWin script." diff --git a/uninstall.sh b/uninstall.sh index 75b0c63..8e4e956 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -10,7 +10,7 @@ exit_w_error() { } remove_w_kpackagetool6() { - if command -v kpackagetool6; then + if command -v kpackagetool6 &> /dev/null; then echo "Removing 'Application Switcher' KWin script." kpackagetool6 --type=KWin/Script --remove . else @@ -19,7 +19,7 @@ remove_w_kpackagetool6() { } remove_w_kpackagetool5() { - if command -v kpackagetool5; then + if command -v kpackagetool5 &> /dev/null; then echo "Removing 'Application Switcher' KWin script." kpackagetool5 --type=KWin/Script --remove . else From 7f8fc8e52c19f25fd291ef1c793427158d6ff8af Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Mon, 20 Nov 2023 03:13:35 -0900 Subject: [PATCH 05/28] Suppress install error before trying upgrade --- install.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index ff72267..12242b4 100755 --- a/install.sh +++ b/install.sh @@ -11,14 +11,16 @@ exit_w_error() { install_w_kpackagetool6() { echo "Installing KWin script: '${script_name}'" - kpackagetool6 --type="${script_type}" --install "${script_path}" || \ + if ! kpackagetool6 --type="${script_type}" --install "${script_path}" &> /dev/null; then kpackagetool6 --type="${script_type}" --upgrade "${script_path}" + fi } install_w_kpackagetool5() { echo "Installing KWin script: '${script_name}'" - kpackagetool5 --type="${script_type}" --install "${script_path}" || \ + if ! kpackagetool5 --type="${script_type}" --install "${script_path}" &> /dev/null; then kpackagetool5 --type="${script_type}" --upgrade "${script_path}" + fi } KDE_ver=${KDE_SESSION_VERSION:-0} From fb16bf31e84cd1adcb4409504186e8ea95ff6c4a Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Mon, 20 Nov 2023 03:39:39 -0900 Subject: [PATCH 06/28] Suppress strange output from reconfigure command --- install.sh | 6 +++--- uninstall.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index 12242b4..0bfbaaf 100755 --- a/install.sh +++ b/install.sh @@ -84,9 +84,9 @@ for cmd in "${dbus_commands[@]}"; do if command -v "${cmd}" &> /dev/null; then # Call the corresponding function based on the command case "$cmd" in - qdbus) reconfigure_w_qdbus ;; - gdbus) reconfigure_w_gdbus ;; - dbus-send) reconfigure_w_dbus_send ;; + qdbus) reconfigure_w_qdbus &> /dev/null;; + gdbus) reconfigure_w_gdbus &> /dev/null ;; + dbus-send) reconfigure_w_dbus_send &> /dev/null ;; esac # Break out of the loop once a command is found and executed break diff --git a/uninstall.sh b/uninstall.sh index 8e4e956..2e7348d 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -67,9 +67,9 @@ for cmd in "${dbus_commands[@]}"; do if command -v "${cmd}" &> /dev/null; then # Call the corresponding function based on the command case "$cmd" in - qdbus) reconfigure_w_qdbus ;; - gdbus) reconfigure_w_gdbus ;; - dbus-send) reconfigure_w_dbus_send ;; + qdbus) reconfigure_w_qdbus &> /dev/null;; + gdbus) reconfigure_w_gdbus &> /dev/null ;; + dbus-send) reconfigure_w_dbus_send &> /dev/null ;; esac # Break out of the loop once a command is found and executed break From 1f6eb312aa464cfcce713d321025ab9a36561831 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:36:00 -0900 Subject: [PATCH 07/28] Fix for getting desktops on KDE 6 --- contents/code/main.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/contents/code/main.js b/contents/code/main.js index acd7a5f..a6bc48c 100644 --- a/contents/code/main.js +++ b/contents/code/main.js @@ -21,6 +21,7 @@ let activeWindow; let windowList; let connectWindowActivated; let setActiveWindow; +let isAppOnCurrentDesktop; // Set up aliases to abstract away the API differences between KDE 5 and KDE 6 if (isKDE6) { @@ -28,11 +29,17 @@ if (isKDE6) { windowList = () => workspace.windowList(); connectWindowActivated = (handler) => workspace.windowActivated.connect(handler); setActiveWindow = (window) => { workspace.activeWindow = window; }; + isAppOnCurrentDesktop = (window) => + (window.desktops && window.desktops.includes(workspace.currentDesktop)) || + (window.desktops && window.desktops.length === 0); } else { activeWindow = () => workspace.activeClient; windowList = () => workspace.clientList(); connectWindowActivated = (handler) => workspace.clientActivated.connect(handler); setActiveWindow = (window) => { workspace.activeClient = window; }; + isAppOnCurrentDesktop = (window) => + (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || + (window.x11DesktopIds && window.x11DesktopIds.length === 0); } /////////////////////// @@ -103,22 +110,21 @@ function updateAppGroups(current) { )); } +function isAppOnCurrentActivity(window) { + return (window.activities && window.activities.includes(workspace.currentActivity)) || + (window.activities && window.activities.length === 0); +} + +function getFilterConditions(window) { + return window && !window.minimized && + isAppOnCurrentDesktop(window) && isAppOnCurrentActivity(window); +} + // return other visible windows of same application as given window function getAppGroup(current) { if (!current) return; - let appGroup = appGroups[getApp(current)].filter(window => - window && - !window.minimized && - ( - (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || - (window.x11DesktopIds && window.x11DesktopIds.length === 0) - ) && - ( - (window.activities && window.activities.includes(workspace.currentActivity)) || - (window.activities && window.activities.length === 0) - ) - ); + let appGroup = appGroups[getApp(current)].filter(getFilterConditions); debug("getting app group", appGroup.map(window => window && window.caption ? window.caption : "undefined window" From 0183050d99c93809b6dfae3f9055e478ff466e71 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:53:51 -0900 Subject: [PATCH 08/28] Enhance app group debugging output --- contents/code/main.js | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/contents/code/main.js b/contents/code/main.js index a6bc48c..c3497b5 100644 --- a/contents/code/main.js +++ b/contents/code/main.js @@ -17,6 +17,18 @@ debug("initializing"); // Detect KDE version const isKDE6 = typeof workspace.windowList === 'function'; +function isAppOnCurrentDesktopKDE6(window) { + return window && + (window.desktops && window.desktops.includes(workspace.currentDesktop)) || + (window.desktops && window.desktops.length === 0); +} + +function isAppOnCurrentDesktopKDE5(window) { + return window && + (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || + (window.x11DesktopIds && window.x11DesktopIds.length === 0); +} + let activeWindow; let windowList; let connectWindowActivated; @@ -29,17 +41,13 @@ if (isKDE6) { windowList = () => workspace.windowList(); connectWindowActivated = (handler) => workspace.windowActivated.connect(handler); setActiveWindow = (window) => { workspace.activeWindow = window; }; - isAppOnCurrentDesktop = (window) => - (window.desktops && window.desktops.includes(workspace.currentDesktop)) || - (window.desktops && window.desktops.length === 0); + isAppOnCurrentDesktop = isAppOnCurrentDesktopKDE6 } else { activeWindow = () => workspace.activeClient; windowList = () => workspace.clientList(); connectWindowActivated = (handler) => workspace.clientActivated.connect(handler); setActiveWindow = (window) => { workspace.activeClient = window; }; - isAppOnCurrentDesktop = (window) => - (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || - (window.x11DesktopIds && window.x11DesktopIds.length === 0); + isAppOnCurrentDesktop = isAppOnCurrentDesktopKDE5 } /////////////////////// @@ -123,10 +131,15 @@ function getFilterConditions(window) { // return other visible windows of same application as given window function getAppGroup(current) { if (!current) return; - - let appGroup = appGroups[getApp(current)].filter(getFilterConditions); - debug("getting app group", appGroup.map(window => + unfilteredAppGroup = appGroups[getApp(current)]; + debug("unfiltered app group", unfilteredAppGroup.map(window => + window && window.caption ? window.caption : "undefined window")); + + // let appGroup = appGroups[getApp(current)].filter(getFilterConditions); + let appGroup = unfilteredAppGroup.filter(getFilterConditions); + + debug("filtered app group", appGroup.map(window => window && window.caption ? window.caption : "undefined window" )); return appGroup; From 27b3c84c6b4a4911a9c7536fa7c8bb7108148323 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:30:06 -0900 Subject: [PATCH 09/28] Rework install/uninstall scripts --- install.sh | 73 ++++++++++++++++++++++++++++++---------------------- uninstall.sh | 56 ++++++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 48 deletions(-) diff --git a/install.sh b/install.sh index 0bfbaaf..d951c92 100755 --- a/install.sh +++ b/install.sh @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# This is a script to install the "Application Switcher" KWin script +# This script will install a KWin script structure found in the path designated in '$script_path' exit_w_error() { local msg="$1" - echo -e "\n(EE) ERROR: ${msg} Exiting...\n" + echo -e "\nERROR: ${msg} \nExiting...\n" exit 1 } install_w_kpackagetool6() { + if ! command -v kpackagetool6 &> /dev/null; then + exit_w_error "The 'kpackagetool6' command was not found. Cannot install KWin script." + fi echo "Installing KWin script: '${script_name}'" if ! kpackagetool6 --type="${script_type}" --install "${script_path}" &> /dev/null; then kpackagetool6 --type="${script_type}" --upgrade "${script_path}" @@ -17,49 +20,55 @@ install_w_kpackagetool6() { } install_w_kpackagetool5() { + if ! command -v kpackagetool5 &> /dev/null; then + exit_w_error "The 'kpackagetool${KDE_ver}' command was not found." + fi echo "Installing KWin script: '${script_name}'" if ! kpackagetool5 --type="${script_type}" --install "${script_path}" &> /dev/null; then kpackagetool5 --type="${script_type}" --upgrade "${script_path}" fi } -KDE_ver=${KDE_SESSION_VERSION:-0} +KDE_ver=${KDE_SESSION_VERSION:-0} # Default to zero value if environment variable not set script_type="KWin/Script" script_path="." -script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') - -if [[ ${KDE_ver} -eq 6 ]]; then - if command -v kpackagetool6 &> /dev/null; then - if install_w_kpackagetool6; then - if command -v kwriteconfig6 &> /dev/null; then - kwriteconfig6 --file kwinrc --group Plugins --key "$script_name"Enabled true - else - exit_w_error "The 'kwriteconfig6' command was not found. Cannot enable KWin script." - fi - else - exit_w_error "Problem installing '${script_name}' with kpackagetool6." - fi - else - echo "The 'kpackagetool6' command was not found. Cannot install KWin script." + + +if [ -f "./metadata.json" ]; then + script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') +elif [ -f "./metadata.desktop" ]; then + script_name=$(grep '^X-KDE-PluginInfo-Name=' ./metadata.desktop | cut -d '=' -f2) +else + exit_w_error "No suitable metadata file found. Unable to get script name." +fi + + +if [[ ${KDE_ver} -eq 0 ]]; then + echo "KDE_SESSION_VERSION environment variable was not set." + exit_w_error "Cannot install '${script_name}' KWin script." +elif [[ ${KDE_ver} -eq 6 ]]; then + if ! install_w_kpackagetool6; then + exit_w_error "Problem installing '${script_name}' with kpackagetool6." + fi + if ! command -v kwriteconfig6 &> /dev/null; then + exit_w_error "The 'kwriteconfig6' command was not found. Cannot enable KWin script." fi + kwriteconfig6 --file kwinrc --group Plugins --key "$script_name"Enabled true elif [[ ${KDE_ver} -eq 5 ]]; then - if command -v kpackagetool5 &> /dev/null; then - if install_w_kpackagetool5; then - if command -v kwriteconfig5 &> /dev/null; then - kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true - else - exit_w_error "The 'kwriteconfig5' command was not found. Cannot enable KWin script." - fi - else - exit_w_error "Problem installing '${script_name}' with kpackagetool5." - fi - else - exit_w_error "The 'kpackagetool5' command was not found." + if ! install_w_kpackagetool5; then + exit_w_error "Problem installing '${script_name}' with kpackagetool${KDE_ver}." fi + if ! command -v kwriteconfig5 &> /dev/null; then + exit_w_error "The 'kwriteconfig5' command was not found. Cannot enable KWin script." + fi + kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true else - exit_w_error "KDE version not recognized. Cannot install the KWin script." + exit_w_error "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" fi + +sleep 0.5 + # We need to gracefully cascade through common D-Bus utils to # find one that is available to use for the KWin reconfigure # command. Sometimes 'qdbus' is not available. @@ -83,11 +92,13 @@ reconfigure_w_dbus_send() { for cmd in "${dbus_commands[@]}"; do if command -v "${cmd}" &> /dev/null; then # Call the corresponding function based on the command + echo "Refreshing KWin configuration." case "$cmd" in qdbus) reconfigure_w_qdbus &> /dev/null;; gdbus) reconfigure_w_gdbus &> /dev/null ;; dbus-send) reconfigure_w_dbus_send &> /dev/null ;; esac + sleep 0.5 # Break out of the loop once a command is found and executed break fi diff --git a/uninstall.sh b/uninstall.sh index 2e7348d..6085b6b 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,48 +1,66 @@ #!/usr/bin/env bash -# This is a script to remove the "Application Switcher" KWin script +# This is a script to remove an installed KWin script matching a script found in the current folder exit_w_error() { local msg="$1" - echo -e "\n(EE) ERROR: ${msg} Exiting...\n" + echo -e "\nERROR: ${msg} \nExiting...\n" exit 1 } remove_w_kpackagetool6() { - if command -v kpackagetool6 &> /dev/null; then - echo "Removing 'Application Switcher' KWin script." - kpackagetool6 --type=KWin/Script --remove . - else + if ! command -v kpackagetool6 &> /dev/null; then exit_w_error "The 'kpackagetool6' command is missing. Cannot remove KWin script." + else + echo "Removing '${script_name}' KWin script." + kpackagetool6 --type=${script_type} --remove ${script_path} fi } remove_w_kpackagetool5() { - if command -v kpackagetool5 &> /dev/null; then - echo "Removing 'Application Switcher' KWin script." - kpackagetool5 --type=KWin/Script --remove . - else + if ! command -v kpackagetool5 &> /dev/null; then exit_w_error "The 'kpackagetool5' command is missing. Cannot remove KWin script." + else + echo "Removing '${script_name}' KWin script." + kpackagetool5 --type=${script_type} --remove ${script_path} fi } -KDE_ver=${KDE_SESSION_VERSION:-0} +KDE_ver=${KDE_SESSION_VERSION:-0} # Default to zero value if environment variable not set +script_type="KWin/Script" +script_path="." + + +if [ -f "./metadata.json" ]; then + script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') +elif [ -f "./metadata.desktop" ]; then + script_name=$(grep '^X-KDE-PluginInfo-Name=' ./metadata.desktop | cut -d '=' -f2) +else + exit_w_error "No suitable metadata file found. Unable to get script name." +fi -if [[ $KDE_ver -eq 6 ]]; then - if remove_w_kpackagetool6; then - echo "KWin script removed." +if [[ $KDE_ver -eq 0 ]]; then + echo "KDE_SESSION_VERSION environment variable was not set." + exit_w_error "Cannot remove '${script_name}' KWin script." +elif [[ $KDE_ver -eq 6 ]]; then + if ! remove_w_kpackagetool6; then + exit_w_error "Problem while removing '${script_name}' KWin script." fi + echo "'${script_name}' KWin script removed. Refreshing KWin." elif [[ ${KDE_ver} -eq 5 ]]; then - if remove_w_kpackagetool5; then - echo "KWin script removed." + if ! remove_w_kpackagetool5; then + exit_w_error "Problem while removing '${script_name}' KWin script." fi + echo "'${script_name}' KWin script removed. Refreshing KWin." else - exit_w_error "KDE version not recognized. Cannot remove KWin script." + exit_w_error "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" fi +sleep 0.5 + # We need to gracefully cascade through common D-Bus utils to # find one that is available to use for the KWin reconfigure # command. Sometimes 'qdbus' is not available. @@ -66,12 +84,16 @@ reconfigure_w_dbus_send() { for cmd in "${dbus_commands[@]}"; do if command -v "${cmd}" &> /dev/null; then # Call the corresponding function based on the command + echo "Refreshing KWin configuration." case "$cmd" in qdbus) reconfigure_w_qdbus &> /dev/null;; gdbus) reconfigure_w_gdbus &> /dev/null ;; dbus-send) reconfigure_w_dbus_send &> /dev/null ;; esac + sleep 0.5 # Break out of the loop once a command is found and executed break fi done + +echo "Finished removing KWin script: '${script_name}'" From d3cb8077d0adebff2d3f249c7bccedb0eac93c9e Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:33:15 -0900 Subject: [PATCH 10/28] Version bump in READMEs --- README.bbcode | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.bbcode b/README.bbcode index 09ed4fe..962bd19 100644 --- a/README.bbcode +++ b/README.bbcode @@ -1,6 +1,6 @@ Automatically raises all other visible windows of the same application together when activating one of them, effectively creating application groups to task-switch between. -[b]Please make sure to install the most recent version (v1.6) and to not use Discover for installation.[/b] For more information on installation, setup and usage as well as any requests, please visit [url=https://github.com/nclarius/kwin-application-switcher]the GitHub page[/url]. +[b]Please make sure to install the most recent version (v1.7) and to not use Discover for installation.[/b] For more information on installation, setup and usage as well as any requests, please visit [url=https://github.com/nclarius/kwin-application-switcher]the GitHub page[/url]. This extension gives rise to an application-centric task switching workflow as known from environments such as GNOME or MacOS, where an application’s windows are treated as a group, and task switching can take place at two levels: one mode for switching applications and one mode for switching between windows of an application. diff --git a/README.md b/README.md index 25a07f6..3dd317d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Seen in the screencast: Switching from Konsole back to Dolphin also brings the o ### Installation via graphical interface -**Please make sure to select the most recent version (v1.6)** in the installation process. +**Please make sure to select the most recent version (v1.7)** in the installation process. A [bug](https://bugs.kde.org/show_bug.cgi?id=453521) in Discover causes a wrong version to be installed, so using the installation module in System Settings instead is recommended. From c2fde482a67a5659f7a1b16781fbc9f453114300 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:33:43 -0900 Subject: [PATCH 11/28] Remove some unneeded files --- application-switcher_v1.6.kwinscript | Bin 18370 -> 0 bytes kde5/contents/code/main.js | 140 --------------------------- kde5/metadata.json | 24 ----- kde6/contents/code/main.js | 140 --------------------------- kde6/metadata.json | 24 ----- 5 files changed, 328 deletions(-) delete mode 100644 application-switcher_v1.6.kwinscript delete mode 100644 kde5/contents/code/main.js delete mode 100644 kde5/metadata.json delete mode 100644 kde6/contents/code/main.js delete mode 100644 kde6/metadata.json diff --git a/application-switcher_v1.6.kwinscript b/application-switcher_v1.6.kwinscript deleted file mode 100644 index 0b77014291013b57959f7309908e151597c54efb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18370 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 y$1Vsr4z?)_Xe5>mVaP^e?h`>a(o&QGv1 -GNU General Public License v3.0 -*/ - -/////////////////////// -// initialization -/////////////////////// - -const debugMode = readConfig("debugMode", true); -function debug(...args) { - if (debugMode) { console.debug("applicationswitcher:", ...args); } -} -debug("initializing"); - - -/////////////////////// -// special applications to ignore -/////////////////////// - -const ignoredApps = ["plasmashell", "org.kde.plasmashell", // desktop shell - "krunner", "org.kde.krunner", // KRunner - "kwin_wayland", // lock screen - "org.kde.ksmserver-logout-greeter", // logout screen - "ksplashqml" // login splash screen - ]; - - -/////////////////////// -// get application a window belongs to -/////////////////////// - -// "dolphin" -function getApp(current) { - if (!current || typeof current.resourceClass !== 'string') return ""; - return String(current.resourceClass); -} - - -/////////////////////// -// keep track of active application (to check whether app has been switched) -/////////////////////// - -// "dolphin" -var prevActiveApp = "" - -// set previously active application for initially active window -setPrevActiveApp(workspace.activeClient); - -// set previously active application for recently activated window -function setPrevActiveApp(current) { - if (!current) return; - prevActiveApp = getApp(current); -} - -// get previously active application -function getPrevActiveApp() { - return prevActiveApp; -} - - -/////////////////////// -// keep track of windows belonging to same application in order of activation -/////////////////////// - -// {"dolphin": [oldest window, ..., most recent window], "konsole": ...} -var appGroups = {}; - -// compute app groups for initially present windows -workspace.clientList().forEach(window => updateAppGroups(window)); - -// update app groups with given window -function updateAppGroups(current) { - if (!current) return; - let app = getApp(current); - if (!appGroups[app]) appGroups[app] = []; - appGroups[app] = appGroups[app].filter(window => window && - window != current); - appGroups[app].push(current); - debug("updating app group", appGroups[app].map(window => - window && window.caption ? window.caption : "undefined window" - )); -} - -// return other visible windows of same application as given window -function getAppGroup(current) { - if (!current) return; - - let appGroup = appGroups[getApp(current)].filter(window => - window && - !window.minimized && - ( - (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || - (window.x11DesktopIds && window.x11DesktopIds.length === 0) - ) && - ( - (window.activities && window.activities.includes(workspace.currentActivity)) || - (window.activities && window.activities.length === 0) - ) - ); - - debug("getting app group", appGroup.map(window => - window && window.caption ? window.caption : "undefined window" - )); - return appGroup; -} - - -/////////////////////// -// main -/////////////////////// - -// when client is activated, auto-raise other windows of the same application -workspace.clientActivated.connect(active => { - if (!active) return; - debug("---------"); - debug("activated", active.caption); - debug("app", getApp(active)); - // abort if application is ignored - if (ignoredApps.includes(getApp(active))) { - debug("ignored"); - return; - } - updateAppGroups(active); - - // if application was switched - debug("previous app", getPrevActiveApp()); - if (getApp(active) != getPrevActiveApp()) { - debug("app switched"); - setPrevActiveApp(active); - // auto-raise other windows of same application - for (let window of getAppGroup(active)) { - if (window) { - debug("auto-raising", window.caption); - workspace.activeClient = window; - } - } - } -}); diff --git a/kde5/metadata.json b/kde5/metadata.json deleted file mode 100644 index f4f10a4..0000000 --- a/kde5/metadata.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "KPackageStructure": "KWin/Script", - "KPlugin": { - "Authors": [ - { - "Email": "natalie_clarius@yahoo.de", - "Name": "Natalie Clarius" - } - ], - "Description": "Collectively raises all windows of the same application when switching tasks", - "Icon": "preferences-system-windows", - "Id": "applicationswitcher", - "License": "GPLv3.0", - "Name": "Application Switcher", - "ServiceTypes": [ - "KWin/Script", - "KCModule" - ], - "Version": "1.6", - "Website": "" - }, - "X-Plasma-API": "javascript", - "X-Plasma-MainScript": "code/main.js" -} diff --git a/kde6/contents/code/main.js b/kde6/contents/code/main.js deleted file mode 100644 index 05d835a..0000000 --- a/kde6/contents/code/main.js +++ /dev/null @@ -1,140 +0,0 @@ -/* -KWin Script Application Switcher -(C) 2022 Natalie Clarius -GNU General Public License v3.0 -*/ - -/////////////////////// -// initialization -/////////////////////// - -const debugMode = readConfig("debugMode", true); -function debug(...args) { - if (debugMode) { console.debug("applicationswitcher:", ...args); } -} -debug("initializing"); - - -/////////////////////// -// special applications to ignore -/////////////////////// - -const ignoredApps = ["plasmashell", "org.kde.plasmashell", // desktop shell - "krunner", "org.kde.krunner", // KRunner - "kwin_wayland", // lock screen - "org.kde.ksmserver-logout-greeter", // logout screen - "ksplashqml" // login splash screen - ]; - - -/////////////////////// -// get application a window belongs to -/////////////////////// - -// "dolphin" -function getApp(current) { - if (!current || typeof current.resourceClass !== 'string') return ""; - return String(current.resourceClass); -} - - -/////////////////////// -// keep track of active application (to check whether app has been switched) -/////////////////////// - -// "dolphin" -var prevActiveApp = "" - -// set previously active application for initially active window -setPrevActiveApp(workspace.activeWindow); - -// set previously active application for recently activated window -function setPrevActiveApp(current) { - if (!current) return; - prevActiveApp = getApp(current); -} - -// get previously active application -function getPrevActiveApp() { - return prevActiveApp; -} - - -/////////////////////// -// keep track of windows belonging to same application in order of activation -/////////////////////// - -// {"dolphin": [oldest window, ..., most recent window], "konsole": ...} -var appGroups = {}; - -// compute app groups for initially present windows -workspace.windowList().forEach(window => updateAppGroups(window)); - -// update app groups with given window -function updateAppGroups(current) { - if (!current) return; - let app = getApp(current); - if (!appGroups[app]) appGroups[app] = []; - appGroups[app] = appGroups[app].filter(window => window && - window != current); - appGroups[app].push(current); - debug("updating app group", appGroups[app].map(window => - window && window.caption ? window.caption : "undefined window" - )); -} - -// return other visible windows of same application as given window -function getAppGroup(current) { - if (!current) return; - - let appGroup = appGroups[getApp(current)].filter(window => - window && - !window.minimized && - ( - (window.x11DesktopIds && window.x11DesktopIds.includes(workspace.currentDesktop)) || - (window.x11DesktopIds && window.x11DesktopIds.length === 0) - ) && - ( - (window.activities && window.activities.includes(workspace.currentActivity)) || - (window.activities && window.activities.length === 0) - ) - ); - - debug("getting app group", appGroup.map(window => - window && window.caption ? window.caption : "undefined window" - )); - return appGroup; -} - - -/////////////////////// -// main -/////////////////////// - -// when window is activated, auto-raise other windows of the same application -workspace.windowActivated.connect(active => { - if (!active) return; - debug("---------"); - debug("activated", active.caption); - debug("app", getApp(active)); - // abort if application is ignored - if (ignoredApps.includes(getApp(active))) { - debug("ignored"); - return; - } - updateAppGroups(active); - - // if application was switched - debug("previous app", getPrevActiveApp()); - if (getApp(active) != getPrevActiveApp()) { - debug("app switched"); - setPrevActiveApp(active); - // auto-raise other windows of same application - for (let window of getAppGroup(active)) { - if (window) { - debug("auto-raising", window.caption); - workspace.activeWindow = window; - } - } - } -}); diff --git a/kde6/metadata.json b/kde6/metadata.json deleted file mode 100644 index f4f10a4..0000000 --- a/kde6/metadata.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "KPackageStructure": "KWin/Script", - "KPlugin": { - "Authors": [ - { - "Email": "natalie_clarius@yahoo.de", - "Name": "Natalie Clarius" - } - ], - "Description": "Collectively raises all windows of the same application when switching tasks", - "Icon": "preferences-system-windows", - "Id": "applicationswitcher", - "License": "GPLv3.0", - "Name": "Application Switcher", - "ServiceTypes": [ - "KWin/Script", - "KCModule" - ], - "Version": "1.6", - "Website": "" - }, - "X-Plasma-API": "javascript", - "X-Plasma-MainScript": "code/main.js" -} From 067f28d20734bb80b5815ff864fde5cc9ca6304a Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Thu, 23 Nov 2023 01:20:30 -0900 Subject: [PATCH 12/28] Add .gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b0037e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +.vscode/settings.json From 043fa3c2a122392ceb505963bfd9579abc8e7471 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Thu, 23 Nov 2023 01:22:43 -0900 Subject: [PATCH 13/28] Remove unwanted VSCode file --- .vscode/settings.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f3e0f5d..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "settings": { - "workbench.colorCustomizations": { - "titleBar.activeBackground": "#cc00ff23", - "activityBar.background": "#cc00ff23" - } - } -} \ No newline at end of file From e55d0ab89ce2dd01b2a52321b15af83012ce4893 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:13:30 -0900 Subject: [PATCH 14/28] Improve code consistency. --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index d951c92..b493a5c 100755 --- a/install.sh +++ b/install.sh @@ -21,7 +21,7 @@ install_w_kpackagetool6() { install_w_kpackagetool5() { if ! command -v kpackagetool5 &> /dev/null; then - exit_w_error "The 'kpackagetool${KDE_ver}' command was not found." + exit_w_error "The 'kpackagetool5' command was not found. Cannot install KWin script." fi echo "Installing KWin script: '${script_name}'" if ! kpackagetool5 --type="${script_type}" --install "${script_path}" &> /dev/null; then @@ -56,7 +56,7 @@ elif [[ ${KDE_ver} -eq 6 ]]; then kwriteconfig6 --file kwinrc --group Plugins --key "$script_name"Enabled true elif [[ ${KDE_ver} -eq 5 ]]; then if ! install_w_kpackagetool5; then - exit_w_error "Problem installing '${script_name}' with kpackagetool${KDE_ver}." + exit_w_error "Problem installing '${script_name}' with kpackagetool5." fi if ! command -v kwriteconfig5 &> /dev/null; then exit_w_error "The 'kwriteconfig5' command was not found. Cannot enable KWin script." From 189d582ce9511c0d1be8b1adc73eac96e6fdb7ce Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Thu, 9 May 2024 12:34:20 -0800 Subject: [PATCH 15/28] Add v1.7 kwinscript (zip) file --- application-switcher_v1.7.kwinscript | Bin 0 -> 2269 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 application-switcher_v1.7.kwinscript diff --git a/application-switcher_v1.7.kwinscript b/application-switcher_v1.7.kwinscript new file mode 100644 index 0000000000000000000000000000000000000000..6488cc69d3e7d905a02a822942ad6401834d9e2d GIT binary patch literal 2269 zcmb7`c`zI58pczxrnaLgLM^4KT8|}EZ>vRZvE&4`G!!YZq_z@`qqN6CsI3l4Y8gb7 zrnN+4YY}TLu@%)erKC|ssb~?Es>_{w=AOB8XYRevJM+EY_s92re?0HZ??KuD`N06; z{i1^KZh(IZCk+4y0h9qD=%7#?Y^2L2F@R95nm49Q+rmS^j6O25CKAFH5 z&aKQVt2MWHW#^h@+P?K0$M!=X!HV2m1|mrJO~><=Vl6Sbo@CB8i`~b`40O^5$w2>j z?8-5~CyutLevff*HTM&UQ*4Xj%CwS-Y@NDzF`2e3ZHBrVxaQWNq7_%s;zh!G63(Y6 zh(MvcJBvqHwanRGH2b*u1@DL?#*@j-lChn6@ab_juN31j@g&gk>vT*2H(QI5;z9XVJ`U_{+U>VUg2%OI_s!i{~!RcrhR=q$`u0MjhSu^mRY>)L}|c4Qn_pKislH zzvhet(VXcF^Y(VTq~)VIk8(Lt`6h4OJa|^$uVC0e{MFfT8NV5WT8`>`5=h zR$F3VClS*;wTCrOA?w7mcr7Z+OsSe^{x?w@2>aK|Y`1Yp9#`DXd3$FwFbev?uB~3& zq-Sg;GyKCqQ}dV6a_fxwPb#od>pjKFOy|}$FSwy3j+1(e#utz`K2y!J(hBcM_C0fY z#bTmsRh=@*1*Z!#%vOP+uZ}7M?vOws`-R@lF_o zN+$yKSM{*vRXv0osMLz8%_XTM+J#py9vHHcNQ_7H)0pX$Ih*%^&cEloFF(+^7DNfv zeIYrkvp@sK2I+j}WR%5vrqrYK6!EJfF7H>N4kf}L2{{CUb~k>VkPW9;Xh$Y$ID!!N z@_kO}k)1P>T&nT;!*7{F&x+GE!WA%sYlam^i72`tt*Zk5v!sZMbh6C!Y|W_~d_gzR zmiC7`c4mi+EMxp|H7SX<*xnAoV&IOlk@Q`6r zQynK9=qzFQ^_|IEv#vD@SzDo8L}4@L_Vv$Ggb@j3#6oInFPmIpQnVQY88T@*LjOr} zBH9D7bii-UP=^N?iqE)lrhmzhj_e3<@ zxM&1AJ~2WP5&IQt8N!$!9&v!RyuQ@XXw@|yvPDhMb1e2hn&f+t@c3tVJ2vJ{5H!j~ zS#)F<-p+uPKYc4E(M@*mlu{kxW*J!N7G=-rtoowdGEzqF=FD$(EY zy8A*pSEjEs(u5HOKqI1x{FZ?4(RZ}oSFgd76wA*`fSspPMOwjXEmu>A?U=3*Ev1_c z0`kMrDlJ-d?q_uFthf#<&{q90NjK+|$Ws`l+Uj5lDo^9KFgBz?4?8r;#&)i5@hlYM zEtr~`UN2J&ax}WO)2))f_Y-ONkNw6}ioRC)R?=vuJbaEd=LJpq94cp8iPc6x(c5zo zHsX@OUW|)ieAUrd&ME9dt|HDvU2D%F{g>TTUIWc=Byl>G*CDp85veX_Ul1uLzCj#H zntV?1!n^&@8%N2WLp)VEja)VXiHG&HF3nW5tQ9lH%o2h(qUMx{O}!vi<=B|>1rxJR zUwmvqasjiriE*pf++96mu5~g(foKU7Kk`XLbd}Y|xUYV4>4$`VD_UWLDq+8=vn6lZ z+-mSn@vGYWuGyBr10e)KV!dW8+5TD89^?BGBxCPv)=Guo@{SDBPDr>PjiSp50sse4 zLH!=q0;FGtFDk5_cJQRGor_Pd)gc{o|Uy=@Qvt3vYW#oCFQT3@V7JmDspN%vaV zr`3uyjGTDOWpLO4oaN*@phh1V*ijI41jY@RQcxZVKfxuikuk=Z@>G95?NOYXQ{Xlk}fLn#Yf`lDNGku0=Ge!jKgfuY5Xd4eV< zzw- Date: Sat, 11 May 2024 15:52:20 -0800 Subject: [PATCH 16/28] Create kwinscript file like previous version --- application-switcher_v1.7.kwinscript | Bin 2269 -> 20886 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/application-switcher_v1.7.kwinscript b/application-switcher_v1.7.kwinscript index 6488cc69d3e7d905a02a822942ad6401834d9e2d..a734b67ff1322c6e26ed28ed4ceb92381bef3d20 100644 GIT binary patch delta 18514 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 bVBl?Ik0%4}Do2iw6WEc|0(LFK{6Ja&HP_Vi delta 109 zcmbQXnDMTlT!1$-iwFY;5N_lu4`+aa5-|n_b_NB8jr*h7CeG#A{J?q&<794sDIt&` t3@m8`u_o?UpL{+*V6tX_6mvcs!{q1IdXpOhIrx|um>4zy<;6KbssQ0379jut From 38bd1be83960fe19e656dc9b16154ba66ec6fcd2 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 14:53:27 -0800 Subject: [PATCH 17/28] Use correct remove syntax in uninstall script --- uninstall.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uninstall.sh b/uninstall.sh index 6085b6b..d2d2147 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -14,7 +14,7 @@ remove_w_kpackagetool6() { exit_w_error "The 'kpackagetool6' command is missing. Cannot remove KWin script." else echo "Removing '${script_name}' KWin script." - kpackagetool6 --type=${script_type} --remove ${script_path} + kpackagetool6 --type=${script_type} --remove "${script_name}" fi } @@ -23,13 +23,13 @@ remove_w_kpackagetool5() { exit_w_error "The 'kpackagetool5' command is missing. Cannot remove KWin script." else echo "Removing '${script_name}' KWin script." - kpackagetool5 --type=${script_type} --remove ${script_path} + kpackagetool5 --type=${script_type} --remove "${script_name}" fi } KDE_ver=${KDE_SESSION_VERSION:-0} # Default to zero value if environment variable not set script_type="KWin/Script" -script_path="." +script_name="" if [ -f "./metadata.json" ]; then From 56807b30f5634a5a8c83bcf82861b5ab703b6c76 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 15:00:10 -0800 Subject: [PATCH 18/28] Less redundant log messages --- uninstall.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uninstall.sh b/uninstall.sh index d2d2147..fed3961 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -48,12 +48,12 @@ elif [[ $KDE_ver -eq 6 ]]; then if ! remove_w_kpackagetool6; then exit_w_error "Problem while removing '${script_name}' KWin script." fi - echo "'${script_name}' KWin script removed. Refreshing KWin." + echo "KWin script '${script_name}' was removed." elif [[ ${KDE_ver} -eq 5 ]]; then if ! remove_w_kpackagetool5; then exit_w_error "Problem while removing '${script_name}' KWin script." fi - echo "'${script_name}' KWin script removed. Refreshing KWin." + echo "KWin script '${script_name}' was removed." else exit_w_error "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" fi From 973a4deed6f4d5005f0df536e53c2026eaf61877 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 16:33:23 -0800 Subject: [PATCH 19/28] Update KDE version error log message --- install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index b493a5c..6bcf1cf 100755 --- a/install.sh +++ b/install.sh @@ -63,7 +63,8 @@ elif [[ ${KDE_ver} -eq 5 ]]; then fi kwriteconfig5 --file kwinrc --group Plugins --key "$script_name"Enabled true else - exit_w_error "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" + echo "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" + exit_w_error "This script is meant to run only on KDE 5 or 6." fi From 1184593b97328030d084762ea2a1516f86eafc2e Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 16:36:13 -0800 Subject: [PATCH 20/28] Unload scripts if possible before removing --- uninstall.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/uninstall.sh b/uninstall.sh index fed3961..994a999 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -9,6 +9,47 @@ exit_w_error() { exit 1 } +unload_script() { + echo "Attempting to unload KWin script '${script_name}' prior to removal." + + local success=0 + + if command -v qdbus &> /dev/null; then + qdbus org.kde.KWin /KWin unloadScript "${script_name}" + success=$? + elif command -v gdbus &> /dev/null; then + gdbus call --session --dest org.kde.KWin --object-path /KWin \ + --method org.kde.KWin.unloadScript "${script_name}" + success=$? + elif command -v dbus-send &> /dev/null; then + dbus-send --session --type=method_call --dest=org.kde.KWin /KWin \ + org.kde.KWin.unloadScript string:"${script_name}" + success=$? + else + echo "No available D-Bus utility to unload the KWin script." + echo "You may need to log out to remove the KWin script from memory." + success=1 # Indicates failure to unload due to lack of tools + fi + + + if [[ $success -eq 0 ]]; then + echo "Successfully unloaded the KWin script." + else + echo "ERROR: Failed to unload the KWin script. Look for an error displayed above." + echo "Uninstalling the script now may leave it active in memory until you log out." + read -r -p "Continue with uninstalling the script files anyway? [y/N]: " response + case $response in + [Yy]* ) + echo "Proceeding with removal. The KWin script might still be active in memory." + ;; + * ) + echo "Try to unload the script manually from GUI KWin Scripts settings panel." + exit_w_error "Run this script again to uninstall, or click trash icon in GUI and Apply." + ;; + esac + fi +} + remove_w_kpackagetool6() { if ! command -v kpackagetool6 &> /dev/null; then exit_w_error "The 'kpackagetool6' command is missing. Cannot remove KWin script." @@ -45,17 +86,20 @@ if [[ $KDE_ver -eq 0 ]]; then echo "KDE_SESSION_VERSION environment variable was not set." exit_w_error "Cannot remove '${script_name}' KWin script." elif [[ $KDE_ver -eq 6 ]]; then + unload_script if ! remove_w_kpackagetool6; then exit_w_error "Problem while removing '${script_name}' KWin script." fi echo "KWin script '${script_name}' was removed." elif [[ ${KDE_ver} -eq 5 ]]; then + unload_script if ! remove_w_kpackagetool5; then exit_w_error "Problem while removing '${script_name}' KWin script." fi echo "KWin script '${script_name}' was removed." else - exit_w_error "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" + echo "KDE_SESSION_VERSION had a value, but that value was unrecognized: '${KDE_ver}'" + exit_w_error "This script is meant to run only on KDE 5 or 6." fi From f3a0c7f0b007b61ae0a834d241655b42fb5043c5 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 17:34:04 -0800 Subject: [PATCH 21/28] Update D-Bus commands --- uninstall.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/uninstall.sh b/uninstall.sh index 994a999..b1bb4c0 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -15,15 +15,15 @@ unload_script() { local success=0 if command -v qdbus &> /dev/null; then - qdbus org.kde.KWin /KWin unloadScript "${script_name}" + qdbus org.kde.KWin /Scripting org.kde.kwin.Scripting.unloadScript "${script_name}" success=$? elif command -v gdbus &> /dev/null; then - gdbus call --session --dest org.kde.KWin --object-path /KWin \ - --method org.kde.KWin.unloadScript "${script_name}" + gdbus call --session --dest org.kde.KWin --object-path /Scripting \ + --method org.kde.kwin.Scripting.unloadScript "${script_name}" success=$? elif command -v dbus-send &> /dev/null; then - dbus-send --session --type=method_call --dest=org.kde.KWin /KWin \ - org.kde.KWin.unloadScript string:"${script_name}" + dbus-send --session --type=method_call --dest=org.kde.KWin /Scripting \ + org.kde.kwin.Scripting.unloadScript string:"${script_name}" success=$? else echo "No available D-Bus utility to unload the KWin script." @@ -31,7 +31,6 @@ unload_script() { success=1 # Indicates failure to unload due to lack of tools fi - if [[ $success -eq 0 ]]; then echo "Successfully unloaded the KWin script." else From 1ed97ac76b61a9ada6f49072621c3750e4ffbd68 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 18:35:51 -0800 Subject: [PATCH 22/28] Parse output from unloadScript D-Bus commands --- uninstall.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/uninstall.sh b/uninstall.sh index b1bb4c0..ce079b8 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -9,29 +9,30 @@ exit_w_error() { exit 1 } -unload_script() { +unload_kwin_script() { echo "Attempting to unload KWin script '${script_name}' prior to removal." + local output="" local success=0 if command -v qdbus &> /dev/null; then - qdbus org.kde.KWin /Scripting org.kde.kwin.Scripting.unloadScript "${script_name}" - success=$? + output=$(qdbus org.kde.KWin /Scripting org.kde.kwin.Scripting.unloadScript "${script_name}") + [[ "$output" == "true" ]] && success=1 elif command -v gdbus &> /dev/null; then - gdbus call --session --dest org.kde.KWin --object-path /Scripting \ - --method org.kde.kwin.Scripting.unloadScript "${script_name}" - success=$? + output=$(gdbus call --session --dest org.kde.KWin --object-path /Scripting \ + --method org.kde.kwin.Scripting.unloadScript "${script_name}") + [[ "$output" == "(true,)" ]] && success=1 elif command -v dbus-send &> /dev/null; then - dbus-send --session --type=method_call --dest=org.kde.KWin /Scripting \ - org.kde.kwin.Scripting.unloadScript string:"${script_name}" - success=$? + output=$(dbus-send --session --print-reply --type=method_call --dest=org.kde.KWin \ + /Scripting org.kde.kwin.Scripting.unloadScript string:"${script_name}") + echo "$output" | grep -q "boolean true" && success=1 else echo "No available D-Bus utility to unload the KWin script." echo "You may need to log out to remove the KWin script from memory." - success=1 # Indicates failure to unload due to lack of tools + success=0 # Indicates failure to unload due to lack of tools fi - if [[ $success -eq 0 ]]; then + if [[ $success -eq 1 ]]; then echo "Successfully unloaded the KWin script." else echo "ERROR: Failed to unload the KWin script. Look for an error displayed above." @@ -85,13 +86,13 @@ if [[ $KDE_ver -eq 0 ]]; then echo "KDE_SESSION_VERSION environment variable was not set." exit_w_error "Cannot remove '${script_name}' KWin script." elif [[ $KDE_ver -eq 6 ]]; then - unload_script + unload_kwin_script if ! remove_w_kpackagetool6; then exit_w_error "Problem while removing '${script_name}' KWin script." fi echo "KWin script '${script_name}' was removed." elif [[ ${KDE_ver} -eq 5 ]]; then - unload_script + unload_kwin_script if ! remove_w_kpackagetool5; then exit_w_error "Problem while removing '${script_name}' KWin script." fi From 32bb239986c486b4ca92325bcd3381e81fa7d78f Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 19:08:35 -0800 Subject: [PATCH 23/28] Also handle 'false' case from unloadScript --- uninstall.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/uninstall.sh b/uninstall.sh index ce079b8..dfa0471 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -14,18 +14,22 @@ unload_kwin_script() { local output="" local success=0 + local not_loaded=0 if command -v qdbus &> /dev/null; then output=$(qdbus org.kde.KWin /Scripting org.kde.kwin.Scripting.unloadScript "${script_name}") [[ "$output" == "true" ]] && success=1 + [[ "$output" == "false" ]] && not_loaded=1 elif command -v gdbus &> /dev/null; then output=$(gdbus call --session --dest org.kde.KWin --object-path /Scripting \ --method org.kde.kwin.Scripting.unloadScript "${script_name}") [[ "$output" == "(true,)" ]] && success=1 + [[ "$output" == "(false,)" ]] && not_loaded=1 elif command -v dbus-send &> /dev/null; then output=$(dbus-send --session --print-reply --type=method_call --dest=org.kde.KWin \ /Scripting org.kde.kwin.Scripting.unloadScript string:"${script_name}") echo "$output" | grep -q "boolean true" && success=1 + echo "$output" | grep -q "boolean false" && not_loaded=1 else echo "No available D-Bus utility to unload the KWin script." echo "You may need to log out to remove the KWin script from memory." @@ -34,8 +38,13 @@ unload_kwin_script() { if [[ $success -eq 1 ]]; then echo "Successfully unloaded the KWin script." + elif [[ $not_loaded -eq 1 ]]; then + echo "The KWin script was already unloaded or does not exist." else - echo "ERROR: Failed to unload the KWin script. Look for an error displayed above." + echo "ERROR: Failed to unload the KWin script. Here is the output:" + echo "" + echo "$output" + echo "" echo "Uninstalling the script now may leave it active in memory until you log out." read -r -p "Continue with uninstalling the script files anyway? [y/N]: " response case $response in From 7ce44e279b2d71420717910ac471530cd624ac5f Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 19:09:06 -0800 Subject: [PATCH 24/28] Validate script_name variable parsed from metadata --- install.sh | 4 ++++ uninstall.sh | 3 +++ 2 files changed, 7 insertions(+) diff --git a/install.sh b/install.sh index 6bcf1cf..19c71bc 100755 --- a/install.sh +++ b/install.sh @@ -32,6 +32,7 @@ install_w_kpackagetool5() { KDE_ver=${KDE_SESSION_VERSION:-0} # Default to zero value if environment variable not set script_type="KWin/Script" script_path="." +script_name="" if [ -f "./metadata.json" ]; then @@ -42,6 +43,9 @@ else exit_w_error "No suitable metadata file found. Unable to get script name." fi +if [ "$script_name" == "" ]; then + exit_w_error "Failed to parse KWin script name from metadata file." +fi if [[ ${KDE_ver} -eq 0 ]]; then echo "KDE_SESSION_VERSION environment variable was not set." diff --git a/uninstall.sh b/uninstall.sh index dfa0471..ee5d802 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -90,6 +90,9 @@ else exit_w_error "No suitable metadata file found. Unable to get script name." fi +if [ "$script_name" == "" ]; then + exit_w_error "Failed to parse KWin script name from metadata file." +fi if [[ $KDE_ver -eq 0 ]]; then echo "KDE_SESSION_VERSION environment variable was not set." From ab121918c59bd3d7e733e966e1f63d016c93df30 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Sun, 12 May 2024 22:49:22 -0800 Subject: [PATCH 25/28] Update v1.7 kwinscript file --- application-switcher_v1.7.kwinscript | Bin 20886 -> 21620 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/application-switcher_v1.7.kwinscript b/application-switcher_v1.7.kwinscript index a734b67ff1322c6e26ed28ed4ceb92381bef3d20..957b87f816bdc55f421945e6b20321ba14900b2c 100644 GIT binary patch delta 3644 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 Date: Thu, 18 Jul 2024 11:22:48 -0800 Subject: [PATCH 26/28] Prioritize using 'gdbus' over 'qdbus' --- install.sh | 56 +++++++++++++++++++++++++++----------------- uninstall.sh | 66 +++++++++++++++++++++++++++++++--------------------- 2 files changed, 75 insertions(+), 47 deletions(-) diff --git a/install.sh b/install.sh index 19c71bc..e6d02ca 100755 --- a/install.sh +++ b/install.sh @@ -39,6 +39,7 @@ if [ -f "./metadata.json" ]; then script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') elif [ -f "./metadata.desktop" ]; then script_name=$(grep '^X-KDE-PluginInfo-Name=' ./metadata.desktop | cut -d '=' -f2) + echo "FYI: 'metadata.desktop' files are deprecated. Use 'metadata.json' format." else exit_w_error "No suitable metadata file found. Unable to get script name." fi @@ -76,37 +77,50 @@ sleep 0.5 # We need to gracefully cascade through common D-Bus utils to # find one that is available to use for the KWin reconfigure -# command. Sometimes 'qdbus' is not available. - -# Array of command names of common D-Bus utilities -dbus_commands=("qdbus" "gdbus" "dbus-send") - -reconfigure_w_qdbus() { - qdbus org.kde.KWin /KWin reconfigure -} - -reconfigure_w_gdbus() { - gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure +# command. Sometimes 'qdbus' is not available. Start with 'gdbus'. + +# Extended array of D-Bus command names with prioritized qdbus variants +dbus_commands=("gdbus" "qdbus6" "qdbus-qt6" "qdbus-qt5" "qdbus" "dbus-send") + +# Functions to handle reconfiguration with different dbus utilities +reconfigure() { + case "$1" in + gdbus) + gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure + ;; + qdbus6 | qdbus-qt6 | qdbus-qt5 | qdbus) + "$1" org.kde.KWin /KWin reconfigure + ;; + dbus-send) + dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure + ;; + *) + echo "Unsupported DBus utility: $1" >&2 + return 1 + ;; + esac } -reconfigure_w_dbus_send() { - dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure -} +# Unquoted 'true' and 'false' values are built-in commands in bash, +# returning 0 or 1 exit status. +# So they can sort of be treated like Python's 'True' or 'False' in 'if' conditions. +dbus_cmd_found=false # Iterate through the dbus_commands array for cmd in "${dbus_commands[@]}"; do if command -v "${cmd}" &> /dev/null; then - # Call the corresponding function based on the command - echo "Refreshing KWin configuration." - case "$cmd" in - qdbus) reconfigure_w_qdbus &> /dev/null;; - gdbus) reconfigure_w_gdbus &> /dev/null ;; - dbus-send) reconfigure_w_dbus_send &> /dev/null ;; - esac + dbus_cmd_found=true + echo "Refreshing KWin configuration using $cmd." + reconfigure "${cmd}" &> /dev/null sleep 0.5 # Break out of the loop once a command is found and executed break fi done +if ! $dbus_cmd_found; then + echo "No suitable DBus utility found. KWin configuration may need manual reloading." +fi + + echo "Finished installing KWin script: '${script_name}'" diff --git a/uninstall.sh b/uninstall.sh index ee5d802..c695f01 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -16,15 +16,15 @@ unload_kwin_script() { local success=0 local not_loaded=0 - if command -v qdbus &> /dev/null; then - output=$(qdbus org.kde.KWin /Scripting org.kde.kwin.Scripting.unloadScript "${script_name}") - [[ "$output" == "true" ]] && success=1 - [[ "$output" == "false" ]] && not_loaded=1 - elif command -v gdbus &> /dev/null; then + if command -v gdbus &> /dev/null; then output=$(gdbus call --session --dest org.kde.KWin --object-path /Scripting \ --method org.kde.kwin.Scripting.unloadScript "${script_name}") [[ "$output" == "(true,)" ]] && success=1 [[ "$output" == "(false,)" ]] && not_loaded=1 + elif command -v qdbus &> /dev/null; then + output=$(qdbus org.kde.KWin /Scripting org.kde.kwin.Scripting.unloadScript "${script_name}") + [[ "$output" == "true" ]] && success=1 + [[ "$output" == "false" ]] && not_loaded=1 elif command -v dbus-send &> /dev/null; then output=$(dbus-send --session --print-reply --type=method_call --dest=org.kde.KWin \ /Scripting org.kde.kwin.Scripting.unloadScript string:"${script_name}") @@ -86,6 +86,7 @@ if [ -f "./metadata.json" ]; then script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') elif [ -f "./metadata.desktop" ]; then script_name=$(grep '^X-KDE-PluginInfo-Name=' ./metadata.desktop | cut -d '=' -f2) + echo "FYI: 'metadata.desktop' files are deprecated. Use 'metadata.json' format." else exit_w_error "No suitable metadata file found. Unable to get script name." fi @@ -119,37 +120,50 @@ sleep 0.5 # We need to gracefully cascade through common D-Bus utils to # find one that is available to use for the KWin reconfigure -# command. Sometimes 'qdbus' is not available. - -# Array of command names of common D-Bus utilities -dbus_commands=("qdbus" "gdbus" "dbus-send") - -reconfigure_w_qdbus() { - qdbus org.kde.KWin /KWin reconfigure +# command. Sometimes 'qdbus' is not available. Start with 'gdbus'. + +# Extended array of D-Bus command names with prioritized qdbus variants +dbus_commands=("gdbus" "qdbus6" "qdbus-qt6" "qdbus-qt5" "qdbus" "dbus-send") + +# Functions to handle reconfiguration with different dbus utilities +reconfigure() { + case "$1" in + gdbus) + gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure + ;; + qdbus6 | qdbus-qt6 | qdbus-qt5 | qdbus) + "$1" org.kde.KWin /KWin reconfigure + ;; + dbus-send) + dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure + ;; + *) + echo "Unsupported DBus utility: $1" >&2 + return 1 + ;; + esac } -reconfigure_w_gdbus() { - gdbus call --session --dest org.kde.KWin --object-path /KWin --method org.kde.KWin.reconfigure -} - -reconfigure_w_dbus_send() { - dbus-send --session --type=method_call --dest=org.kde.KWin /KWin org.kde.KWin.reconfigure -} +# Unquoted 'true' and 'false' values are built-in commands in bash, +# returning 0 or 1 exit status. +# So they can sort of be treated like Python's 'True' or 'False' in 'if' conditions. +dbus_cmd_found=false # Iterate through the dbus_commands array for cmd in "${dbus_commands[@]}"; do if command -v "${cmd}" &> /dev/null; then - # Call the corresponding function based on the command - echo "Refreshing KWin configuration." - case "$cmd" in - qdbus) reconfigure_w_qdbus &> /dev/null;; - gdbus) reconfigure_w_gdbus &> /dev/null ;; - dbus-send) reconfigure_w_dbus_send &> /dev/null ;; - esac + dbus_cmd_found=true + echo "Refreshing KWin configuration using $cmd." + reconfigure "${cmd}" &> /dev/null sleep 0.5 # Break out of the loop once a command is found and executed break fi done +if ! $dbus_cmd_found; then + echo "No suitable DBus utility found. KWin configuration may need manual reloading." +fi + + echo "Finished removing KWin script: '${script_name}'" From c60d817d6cb9b6546c1e3ff2e59a694f21a80ade Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Thu, 13 Mar 2025 13:29:25 -0800 Subject: [PATCH 27/28] Work with BSD grep on Chimera Linux --- install.sh | 4 +++- uninstall.sh | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index e6d02ca..07fa655 100755 --- a/install.sh +++ b/install.sh @@ -36,7 +36,9 @@ script_name="" if [ -f "./metadata.json" ]; then - script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') + # The "P" option for grep causes a problem on Chimera Linux, which uses BSD utils + # script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') + script_name=$(grep '"Id":' ./metadata.json | sed 's/.*"Id":[[:space:]]*"\([^"]*\).*/\1/') elif [ -f "./metadata.desktop" ]; then script_name=$(grep '^X-KDE-PluginInfo-Name=' ./metadata.desktop | cut -d '=' -f2) echo "FYI: 'metadata.desktop' files are deprecated. Use 'metadata.json' format." diff --git a/uninstall.sh b/uninstall.sh index c695f01..6da94eb 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -83,7 +83,9 @@ script_name="" if [ -f "./metadata.json" ]; then - script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') + # The "P" option for grep causes a problem on Chimera Linux, which uses BSD utils + # script_name=$(grep -oP '"Id":\s*"[^"]*' ./metadata.json | grep -oP '[^"]*$') + script_name=$(grep '"Id":' ./metadata.json | sed 's/.*"Id":[[:space:]]*"\([^"]*\).*/\1/') elif [ -f "./metadata.desktop" ]; then script_name=$(grep '^X-KDE-PluginInfo-Name=' ./metadata.desktop | cut -d '=' -f2) echo "FYI: 'metadata.desktop' files are deprecated. Use 'metadata.json' format." From e064b988c1a1e4a159486cb47521902a47640473 Mon Sep 17 00:00:00 2001 From: RedBearAK <64876997+RedBearAK@users.noreply.github.com> Date: Thu, 12 Jun 2025 22:14:27 -0800 Subject: [PATCH 28/28] Disable debug output --- contents/code/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contents/code/main.js b/contents/code/main.js index c3497b5..76118b0 100644 --- a/contents/code/main.js +++ b/contents/code/main.js @@ -8,7 +8,9 @@ GNU General Public License v3.0 // initialization /////////////////////// -const debugMode = readConfig("debugMode", true); +// const debugMode = readConfig("debugMode", true); +const debugMode = readConfig("debugMode", false); + function debug(...args) { if (debugMode) { console.debug("applicationswitcher:", ...args); } }