From 2128e6f14e858b9d7abc1f5643cf69270792098c Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 2 Jul 2026 10:59:34 -0400 Subject: [PATCH] compositor/xray: re-add manual bar xray toggle --- quickshell/Common/SettingsData.qml | 18 +----- .../Modules/Settings/CompositorLayoutTab.qml | 22 +++++++ quickshell/Services/HyprlandService.qml | 23 +++++-- quickshell/Services/NiriService.qml | 22 +++++-- .../translations/settings_search_index.json | 60 +++++++++++++++++++ 5 files changed, 120 insertions(+), 25 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index ae0f7769f..e6a21ccf7 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -1016,18 +1016,6 @@ Singleton { } ] - // Bar xray is only safe when no window can end up underneath: auto-hide and overlay-layer - // bars float over windows, and negative spacing pulls windows under the strip - function _standaloneBarXrayAvailable(configs) { - const list = configs || []; - const activeBars = list.filter(c => c && c.enabled && (c.visible ?? true)); - const gapsOverride = (typeof CompositorService !== "undefined" && CompositorService.isHyprland) ? hyprlandLayoutGapsOverride : niriLayoutGapsOverride; - const layoutGaps = gapsOverride >= 0 ? gapsOverride : Math.max(4, (list[0]?.spacing ?? 4)); - return activeBars.every(c => !c.autoHide && !(c.useOverlayLayer ?? false) && (c.spacing ?? 4) + (c.bottomGap ?? 0) + layoutGaps >= 0); - } - - readonly property bool standaloneBarXrayAvailable: _standaloneBarXrayAvailable(barConfigs) - property bool desktopClockEnabled: false property string desktopClockStyle: "analog" property real desktopClockTransparency: 0.8 @@ -2430,17 +2418,13 @@ Singleton { if (index === -1) return; const positionChanged = updates.position !== undefined && configs[index].position !== updates.position; - const barXrayTargetWasAvailable = _standaloneBarXrayAvailable(configs); if (updates.autoHide === false || updates.visible === false) setBarIpcReveal(barId, false); Object.assign(configs[index], updates); - const sanitizedConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs; - barConfigs = sanitizedConfigs; + barConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs; updateBarConfigs(); - if (!frameEnabled && _standaloneBarXrayAvailable(sanitizedConfigs) !== barXrayTargetWasAvailable) - updateCompositorLayout(); if (positionChanged) { NotificationService.dismissAllPopups(); } diff --git a/quickshell/Modules/Settings/CompositorLayoutTab.qml b/quickshell/Modules/Settings/CompositorLayoutTab.qml index 4a7668b10..839f1b147 100644 --- a/quickshell/Modules/Settings/CompositorLayoutTab.qml +++ b/quickshell/Modules/Settings/CompositorLayoutTab.qml @@ -372,6 +372,17 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`; checked: NiriService.layoutXrayEnabled onToggled: checked => NiriService.setLayoutXray(checked) } + + SettingsToggleRow { + // Hidden in Frame Connected mode, where it has no target + visible: CompositorService.isNiri && !SettingsData.connectedFrameModeActive + tags: ["niri", "xray", "bar", "frame", "performance"] + settingKey: "niriLayoutBarXrayEnabled" + text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray") + description: I18n.tr("Always blur against the wallpaper, even with Xray off") + checked: NiriService.layoutBarXrayEnabled + onToggled: checked => NiriService.setLayoutBarXray(checked) + } } SettingsCard { @@ -488,6 +499,17 @@ awk '$1 == "xray" { print FILENAME ":" FNR; exit }' $files 2>/dev/null`; checked: HyprlandService.layoutXrayEnabled onToggled: checked => HyprlandService.setLayoutXray(checked) } + + SettingsToggleRow { + // Hidden in Frame Connected mode, where it has no target + visible: CompositorService.isHyprland && !SettingsData.connectedFrameModeActive + tags: ["hyprland", "xray", "bar", "frame", "performance"] + settingKey: "hyprlandLayoutBarXrayEnabled" + text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray") + description: I18n.tr("Always blur against the wallpaper, even with Xray off") + checked: HyprlandService.layoutBarXrayEnabled + onToggled: checked => HyprlandService.setLayoutBarXray(checked) + } } SettingsCard { diff --git a/quickshell/Services/HyprlandService.qml b/quickshell/Services/HyprlandService.qml index 77922ff55..b10427ae0 100644 --- a/quickshell/Services/HyprlandService.qml +++ b/quickshell/Services/HyprlandService.qml @@ -34,6 +34,7 @@ Singleton { // dms/layout.lua is the source of truth for xray; parsed once before the first regeneration property bool layoutXrayEnabled: false + property bool layoutBarXrayEnabled: true property bool _layoutXrayLoaded: false property bool _layoutXrayLoading: false @@ -273,6 +274,12 @@ Singleton { generateLayoutConfig(); } + function setLayoutBarXray(enabled) { + layoutBarXrayEnabled = enabled; + _layoutXrayLoaded = true; + generateLayoutConfig(); + } + function loadLayoutXrayState() { if (_layoutXrayLoading) return; @@ -281,7 +288,9 @@ Singleton { Proc.runCommand("hypr-read-layout-xray", ["cat", configDir + "/hypr/dms/layout.lua"], (output, exitCode) => { _layoutXrayLoading = false; if (!_layoutXrayLoaded) { - layoutXrayEnabled = exitCode === 0 && output.includes('"^dms:.*$"'); + const content = exitCode === 0 ? output : ""; + layoutXrayEnabled = content.includes('"^dms:.*$"'); + layoutBarXrayEnabled = !content.includes("-- bar-xray off"); _layoutXrayLoaded = true; } if (layoutGenerationPending) @@ -329,8 +338,8 @@ Singleton { const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled; const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected"; // Hyprland `xray = false` is still early-development; unset already samples real content, so only force xray=true - // Bar/Frame sit flush on the wallpaper, so force the cheap xray blur whenever safe - const barFrameTargetNamespace = !frameEnabled ? (SettingsData.standaloneBarXrayAvailable ? "dms:bar" : null) : (frameConnectedMode ? null : "dms:frame"); + // Connected frame mode has no separate bar/frame surface to target + const barFrameTargetNamespace = !frameEnabled ? "dms:bar" : (frameConnectedMode ? null : "dms:frame"); let content = `-- Auto-generated by DMS — do not edit manually @@ -355,12 +364,18 @@ hl.layer_rule({ }) `; } - if (barFrameTargetNamespace) { + if (layoutBarXrayEnabled && barFrameTargetNamespace) { content += ` hl.layer_rule({ match = { namespace = "^${barFrameTargetNamespace}$" }, xray = true, }) +`; + } + // Marker persists the preference even while the rule has no target + if (!layoutBarXrayEnabled) { + content += ` +-- bar-xray off `; } diff --git a/quickshell/Services/NiriService.qml b/quickshell/Services/NiriService.qml index e3a0d6983..e11bc50bf 100644 --- a/quickshell/Services/NiriService.qml +++ b/quickshell/Services/NiriService.qml @@ -51,6 +51,7 @@ Singleton { // dms/layout.kdl is the source of truth for xray; parsed once before the first regeneration property bool layoutXrayEnabled: true + property bool layoutBarXrayEnabled: true property bool _layoutXrayLoaded: false property bool _layoutXrayLoading: false @@ -1105,6 +1106,12 @@ Singleton { generateNiriLayoutConfig(); } + function setLayoutBarXray(enabled) { + layoutBarXrayEnabled = enabled; + _layoutXrayLoaded = true; + generateNiriLayoutConfig(); + } + function loadLayoutXrayState() { if (_layoutXrayLoading) return; @@ -1113,7 +1120,9 @@ Singleton { Proc.runCommand("niri-read-layout-xray", ["cat", configDir + "/niri/dms/layout.kdl"], (output, exitCode) => { _layoutXrayLoading = false; if (!_layoutXrayLoaded) { - layoutXrayEnabled = exitCode !== 0 || !output.includes("xray false"); + const content = exitCode === 0 ? output : ""; + layoutXrayEnabled = !content.includes("xray false"); + layoutBarXrayEnabled = !content.includes("// bar-xray off"); _layoutXrayLoaded = true; } if (configGenerationPending) @@ -1151,8 +1160,8 @@ Singleton { const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize; const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled; const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected"; - // Bar/Frame sit flush on the wallpaper, so force the cheap xray blur whenever safe - const barFrameTargetNamespace = !frameEnabled ? (SettingsData.standaloneBarXrayAvailable ? "dms:bar" : null) : (frameConnectedMode ? null : "dms:frame"); + // Connected frame mode has no separate bar/frame surface to target + const barFrameTargetNamespace = !frameEnabled ? "dms:bar" : (frameConnectedMode ? null : "dms:frame"); // Xray is niri's default blur, so only the off state needs a rule let xrayRules = ""; @@ -1166,7 +1175,7 @@ layer-rule { }`; } - if (barFrameTargetNamespace) { + if (layoutBarXrayEnabled && barFrameTargetNamespace) { xrayRules += ` layer-rule { @@ -1176,6 +1185,11 @@ layer-rule { } }`; } + // Marker persists the preference even while the rule has no target + if (!layoutBarXrayEnabled) + xrayRules += ` + +// bar-xray off`; const dmsWarning = `// ! DO NOT EDIT ! // ! AUTO-GENERATED BY DMS ! diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 47a9fa501..d02831547 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -8642,6 +8642,66 @@ ], "description": "Width of window border and focus ring" }, + { + "section": "hyprlandLayoutBarXrayEnabled", + "label": "Frame Xray", + "tabIndex": 37, + "category": "Personalization", + "keywords": [ + "against", + "always", + "appearance", + "background", + "bar", + "bg", + "blur", + "custom", + "customize", + "desktop", + "even", + "frame", + "hyprland", + "image", + "performance", + "personal", + "personalization", + "picture", + "wallpaper", + "xray" + ], + "description": "Always blur against the wallpaper, even with Xray off", + "conditionKey": "isHyprland" + }, + { + "section": "niriLayoutBarXrayEnabled", + "label": "Frame Xray", + "tabIndex": 37, + "category": "Personalization", + "keywords": [ + "against", + "always", + "appearance", + "background", + "bar", + "bg", + "blur", + "custom", + "customize", + "desktop", + "even", + "frame", + "image", + "niri", + "performance", + "personal", + "personalization", + "picture", + "wallpaper", + "xray" + ], + "description": "Always blur against the wallpaper, even with Xray off", + "conditionKey": "isNiri" + }, { "section": "hyprlandLayout", "label": "Hyprland Layout Overrides",