From 4cdfc53dcdf44d8034b723a48d66458097c84231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=E1=BB=B3nh=20Thi=E1=BB=87n=20L=E1=BB=99c?= Date: Mon, 31 Aug 2026 01:36:34 +0700 Subject: [PATCH] fix(dock): hide overlay dock over fullscreen (#3224) * fix(dock): hide overlay dock over fullscreen * fix(dock): track fullscreen state declaratively * fix(dock): clear overlay mask during fullscreen * feat(dock): add fullscreen visibility option * fix(dock): preserve auto-hide fullscreen behavior * fix(dock): keep fullscreen mask interactive in overview * fix(frame): host dock on overview without show dock --- quickshell/Common/SettingsData.qml | 1 + quickshell/Common/settings/SettingsSpec.js | 1 + quickshell/Modules/Dock/DockBody.qml | 9 +++++++ quickshell/Modules/Frame/FrameWindow.qml | 3 ++- quickshell/Modules/Settings/DockTab.qml | 10 +++++++ quickshell/Services/CompositorService.qml | 14 ++++++++++ .../translations/settings_search_index.json | 26 +++++++++++++++++++ 7 files changed, 63 insertions(+), 1 deletion(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 907c12bec..a673728c6 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -872,6 +872,7 @@ Singleton { property bool dockAutoHide: false property bool dockSmartAutoHide: false property bool dockUseOverlayLayer: false + property bool dockShowOnFullscreen: false property bool dockGroupByApp: false property bool dockSeparatePinnedAndRunningApps: false property bool dockRestoreSpecialWorkspaceOnClick: false diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 6007a62bd..ccef9e568 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -436,6 +436,7 @@ var SPEC = { dockAutoHide: { def: false }, dockSmartAutoHide: { def: false }, dockUseOverlayLayer: { def: false }, + dockShowOnFullscreen: { def: false }, dockGroupByApp: { def: false }, dockSeparatePinnedAndRunningApps: { def: false }, dockRestoreSpecialWorkspaceOnClick: { def: false }, diff --git a/quickshell/Modules/Dock/DockBody.qml b/quickshell/Modules/Dock/DockBody.qml index 943abbfaf..02e80ad80 100644 --- a/quickshell/Modules/Dock/DockBody.qml +++ b/quickshell/Modules/Dock/DockBody.qml @@ -153,6 +153,8 @@ Item { readonly property string _dockScreenName: dock.modelData ? dock.modelData.name : (dock.screen ? dock.screen.name : "") readonly property bool usesConnectedFrameChrome: CompositorService.usesConnectedFrameChromeForScreen(dock._dockScreenName) readonly property bool usesOverlayLayer: CompositorService.framePeerSurfacesUseOverlayForScreen(dock._dockScreenName) || SettingsData.dockUseOverlayLayer + readonly property bool fullscreenOnScreen: CompositorService.fullscreenToplevelOnScreen(dock._dockScreenName) + readonly property bool hiddenForFullscreen: usesOverlayLayer && fullscreenOnScreen && !SettingsData.dockShowOnFullscreen readonly property bool geometryReady: dock.width > 0 && dock.height > 0 && dockBackground.width > 0 && dockBackground.height > 0 function _syncDockChromeState() { @@ -364,6 +366,9 @@ Item { return true; } + if (hiddenForFullscreen) + return false; + // Smart auto-hide: show dock when no windows overlap, hide when they do if (SettingsData.dockSmartAutoHide) { if (shouldHideForWindows) @@ -470,6 +475,8 @@ Item { return expanded ? Math.min(bodyY - innerReach, dock.height - 1) : dock.height - 1; } width: { + if (dock.hiddenForFullscreen && !expanded) + return 0; if (chrome) return dockMouseArea.width + (isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 + dock.horizontalConnectorExtent * 2 : 0); if (!isVertical) @@ -479,6 +486,8 @@ Item { return atEndEdge ? dock.width - x : Math.max(bodyX + dockBackground.width + innerReach, 1); } height: { + if (dock.hiddenForFullscreen && !expanded) + return 0; if (chrome) return dockMouseArea.height + (!isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 + dock.verticalConnectorExtent * 2 : 0); if (isVertical) diff --git a/quickshell/Modules/Frame/FrameWindow.qml b/quickshell/Modules/Frame/FrameWindow.qml index b74d20ee0..320115a3c 100644 --- a/quickshell/Modules/Frame/FrameWindow.qml +++ b/quickshell/Modules/Frame/FrameWindow.qml @@ -87,7 +87,8 @@ PanelWindow { readonly property bool _connectedActive: CompositorService.usesConnectedFrameChromeForScreen(win.targetScreen) readonly property bool _dockHostedHere: { - if (!win._connectedActive || !SettingsData.showDock || SettingsData.dockUseOverlayLayer) + const dockVisible = SettingsData.showDock || (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview); + if (!win._connectedActive || !dockVisible || SettingsData.dockUseOverlayLayer) return false; const screens = SettingsData.getFilteredScreens("dock"); for (let i = 0; i < screens.length; i++) { diff --git a/quickshell/Modules/Settings/DockTab.qml b/quickshell/Modules/Settings/DockTab.qml index 815ee6517..61034090c 100644 --- a/quickshell/Modules/Settings/DockTab.qml +++ b/quickshell/Modules/Settings/DockTab.qml @@ -98,6 +98,16 @@ Item { visible: SettingsData.showDock onToggled: checked => SettingsData.set("dockUseOverlayLayer", checked) } + + SettingsToggleRow { + settingKey: "dockShowOnFullscreen" + tags: ["dock", "fullscreen", "overlay", "show", "visibility"] + text: I18n.tr("Show Dock Over Fullscreen", "dock visibility toggle") + description: I18n.tr("Keep the dock visible above fullscreen applications", "dock visibility toggle description") + checked: SettingsData.dockShowOnFullscreen + visible: SettingsData.showDock + onToggled: checked => SettingsData.set("dockShowOnFullscreen", checked) + } } SettingsCard { diff --git a/quickshell/Services/CompositorService.qml b/quickshell/Services/CompositorService.qml index c62106143..ceb9a50ed 100644 --- a/quickshell/Services/CompositorService.qml +++ b/quickshell/Services/CompositorService.qml @@ -526,6 +526,20 @@ Singleton { return toplevels; } + function fullscreenToplevelOnScreen(screenOrName) { + const screenName = _screenName(screenOrName); + if (!screenName || !ToplevelManager.toplevels?.values) + return false; + + const toplevels = ToplevelManager.toplevels.values; + for (let i = 0; i < toplevels.length; i++) { + const toplevel = toplevels[i]; + if (toplevel?.fullscreen && toplevel.activated && _toplevelOnScreen(toplevel, screenName)) + return true; + } + return false; + } + function filterCurrentDisplay(toplevels, screenName) { if (!toplevels || toplevels.length === 0 || !screenName) return toplevels; diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 67aaa8aa1..4f7a92a50 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -2252,6 +2252,32 @@ ], "description": "Display a dock with pinned and running applications" }, + { + "section": "dockShowOnFullscreen", + "label": "Show Dock Over Fullscreen", + "tabIndex": 5, + "category": "Dock", + "keywords": [ + "above", + "app", + "applications", + "apps", + "dock", + "fullscreen", + "keep", + "launcher bar", + "over", + "overlay", + "panel", + "program", + "programs", + "show", + "taskbar", + "visibility", + "visible" + ], + "description": "Keep the dock visible above fullscreen applications" + }, { "section": "dockLauncherEnabled", "label": "Show Launcher Button",