diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index b41ab2fa..0c2d0485 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -480,6 +480,7 @@ Singleton { property bool dockAutoHide: false property bool dockSmartAutoHide: false property bool dockGroupByApp: false + property bool dockRestoreSpecialWorkspaceOnClick: false property bool dockOpenOnOverview: false property int dockPosition: SettingsData.Position.Bottom property real dockSpacing: 4 diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index f928b177..f5e2a068 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -295,6 +295,7 @@ var SPEC = { dockAutoHide: { def: false }, dockSmartAutoHide: { def: false }, dockGroupByApp: { def: false }, + dockRestoreSpecialWorkspaceOnClick: { def: false }, dockOpenOnOverview: { def: false }, dockPosition: { def: 1 }, dockSpacing: { def: 4 }, diff --git a/quickshell/Modules/Dock/DockAppButton.qml b/quickshell/Modules/Dock/DockAppButton.qml index 741e3f34..42fe39c5 100644 --- a/quickshell/Modules/Dock/DockAppButton.qml +++ b/quickshell/Modules/Dock/DockAppButton.qml @@ -1,6 +1,7 @@ import QtQuick import QtQuick.Effects import Quickshell +import Quickshell.Hyprland import Quickshell.Wayland import Quickshell.Widgets import qs.Common @@ -133,6 +134,40 @@ Item { function getGroupedToplevels() { return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || []; } + + function getHyprToplevelForWayland(waylandToplevel) { + if (!waylandToplevel || !CompositorService.isHyprland || !Hyprland.toplevels) + return null; + const hyprToplevels = Array.from(Hyprland.toplevels.values); + for (let i = 0; i < hyprToplevels.length; i++) { + if (hyprToplevels[i].wayland === waylandToplevel) + return hyprToplevels[i]; + } + return null; + } + + function getSpecialWorkspaceName(waylandToplevel) { + const hyprToplevel = getHyprToplevelForWayland(waylandToplevel); + if (!hyprToplevel) + return ""; + const wsName = String(hyprToplevel.lastIpcObject?.workspace?.name || hyprToplevel.workspace?.name || ""); + if (!wsName.startsWith("special:")) + return ""; + return wsName.slice("special:".length); + } + + function restoreSpecialWorkspaceWindow(waylandToplevel) { + if (!SettingsData.dockRestoreSpecialWorkspaceOnClick || !CompositorService.isHyprland || !waylandToplevel) + return false; + + const specialName = getSpecialWorkspaceName(waylandToplevel); + if (!specialName) + return false; + + Hyprland.dispatch("togglespecialworkspace " + specialName); + Qt.callLater(() => waylandToplevel.activate()); + return true; + } onIsHoveredChanged: { if (mouseArea.pressed || dragging) return; @@ -276,8 +311,11 @@ Item { break; case "window": const windowToplevel = getToplevelObject(); - if (windowToplevel) + if (windowToplevel) { + if (restoreSpecialWorkspaceWindow(windowToplevel)) + return; windowToplevel.activate(); + } break; case "grouped": if (appData.windowCount === 0) { @@ -300,8 +338,11 @@ Item { SessionService.launchDesktopEntry(groupedEntry); } else if (appData.windowCount === 1) { const groupedToplevel = getToplevelObject(); - if (groupedToplevel) + if (groupedToplevel) { + if (restoreSpecialWorkspaceWindow(groupedToplevel)) + return; groupedToplevel.activate(); + } } else if (contextMenu) { const shouldHidePin = appData.appId === "org.quickshell"; contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); diff --git a/quickshell/Modules/Settings/DockTab.qml b/quickshell/Modules/Settings/DockTab.qml index 2b359de8..9b281a37 100644 --- a/quickshell/Modules/Settings/DockTab.qml +++ b/quickshell/Modules/Settings/DockTab.qml @@ -160,6 +160,16 @@ Item { onToggled: checked => SettingsData.set("dockGroupByApp", checked) } + SettingsToggleRow { + settingKey: "dockRestoreSpecialWorkspaceOnClick" + tags: ["dock", "hyprland", "special", "workspace", "restore"] + text: I18n.tr("Restore Special Workspace Windows") + description: I18n.tr("When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window") + checked: SettingsData.dockRestoreSpecialWorkspaceOnClick + visible: CompositorService.isHyprland + onToggled: checked => SettingsData.set("dockRestoreSpecialWorkspaceOnClick", checked) + } + SettingsButtonGroupRow { settingKey: "dockIndicatorStyle" tags: ["dock", "indicator", "style", "circle", "line"]