diff --git a/Modules/Bar/Extras/BarExclusionZone.qml b/Modules/Bar/Extras/BarExclusionZone.qml index f5333b43d..1e7a9a01d 100644 --- a/Modules/Bar/Extras/BarExclusionZone.qml +++ b/Modules/Bar/Extras/BarExclusionZone.qml @@ -25,7 +25,6 @@ PanelWindow { mask: Region {} // Wayland layer shell configuration - WlrLayershell.layer: WlrLayer.Top WlrLayershell.namespace: "noctalia-bar-exclusion-" + (screen?.name || "unknown") WlrLayershell.exclusionMode: ExclusionMode.Auto diff --git a/Modules/Cards/WeatherCard.qml b/Modules/Cards/WeatherCard.qml index 5a853bd8c..592548f3a 100644 --- a/Modules/Cards/WeatherCard.qml +++ b/Modules/Cards/WeatherCard.qml @@ -61,7 +61,7 @@ NBox { } // Limit update rate to avoid using too much processing power - property real time: parent.shaderTime - (parent.shaderTime % (1 / ( root.isRaining ? 3 : root.isSnowing ? 6 : 2))) + property real time: parent.shaderTime - (parent.shaderTime % (1 / (root.isRaining ? 3 : root.isSnowing ? 6 : 2))) property real itemWidth: weatherEffect.width property real itemHeight: weatherEffect.height property color bgColor: root.color diff --git a/Modules/Dock/Dock.qml b/Modules/Dock/Dock.qml index 62502b32c..303b2457f 100644 --- a/Modules/Dock/Dock.qml +++ b/Modules/Dock/Dock.qml @@ -774,7 +774,6 @@ Loader { margins.left: peekCenterOffsetX WlrLayershell.namespace: "noctalia-dock-indicator-" + (screen?.name || "unknown") - WlrLayershell.layer: WlrLayer.Top WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.keyboardFocus: WlrKeyboardFocus.None implicitHeight: isVertical ? peekEdgeLength : indicatorThickness diff --git a/Modules/MainScreen/BarContentWindow.qml b/Modules/MainScreen/BarContentWindow.qml index 562cb1895..3e5da24b2 100644 --- a/Modules/MainScreen/BarContentWindow.qml +++ b/Modules/MainScreen/BarContentWindow.qml @@ -33,7 +33,6 @@ PanelWindow { // Wayland layer configuration WlrLayershell.namespace: "noctalia-bar-content-" + (barWindow.screen?.name || "unknown") - WlrLayershell.layer: WlrLayer.Top WlrLayershell.exclusionMode: ExclusionMode.Ignore // Don't reserve space - BarExclusionZone in MainScreen handles that // Position and size to match bar location (per-screen) diff --git a/Modules/MainScreen/BarExclusionZone.qml b/Modules/MainScreen/BarExclusionZone.qml index e9696e62e..db97fd8af 100644 --- a/Modules/MainScreen/BarExclusionZone.qml +++ b/Modules/MainScreen/BarExclusionZone.qml @@ -37,7 +37,6 @@ PanelWindow { mask: Region {} // Wayland layer shell configuration - WlrLayershell.layer: WlrLayer.Top WlrLayershell.namespace: "noctalia-bar-exclusion-" + edge + "-" + (screen?.name || "unknown") // When auto-hide, non-exclusive mode is enabled, OR bar is explicitly hidden via IPC, don't reserve space // Note: We check BarService.isVisible directly, NOT effectivelyVisible, because we want diff --git a/Modules/MainScreen/BarTriggerZone.qml b/Modules/MainScreen/BarTriggerZone.qml index b7a9cd58b..ae0538e20 100644 --- a/Modules/MainScreen/BarTriggerZone.qml +++ b/Modules/MainScreen/BarTriggerZone.qml @@ -26,7 +26,6 @@ PanelWindow { focusable: false WlrLayershell.namespace: "noctalia-bar-trigger-" + (screen?.name || "unknown") - WlrLayershell.layer: WlrLayer.Top WlrLayershell.exclusionMode: ExclusionMode.Ignore // Anchor to bar's edge diff --git a/Modules/MainScreen/MainScreen.qml b/Modules/MainScreen/MainScreen.qml index f51ad1157..c7c6f9e81 100644 --- a/Modules/MainScreen/MainScreen.qml +++ b/Modules/MainScreen/MainScreen.qml @@ -44,7 +44,6 @@ PanelWindow { } // Wayland - WlrLayershell.layer: WlrLayer.Top WlrLayershell.namespace: "noctalia-background-" + (screen?.name || "unknown") WlrLayershell.exclusionMode: ExclusionMode.Ignore // Don't reserve space - BarExclusionZone handles that WlrLayershell.keyboardFocus: { @@ -68,18 +67,37 @@ PanelWindow { } anchors { - top: true - bottom: true - left: true - right: true + top: isFramed || _needsFullscreen || _barPosition !== "bottom" + bottom: isFramed || _needsFullscreen || _barPosition !== "top" + left: isFramed || _needsFullscreen || _barPosition !== "right" + right: isFramed || _needsFullscreen || _barPosition !== "left" } + // Implicit sizes control the non-anchored dimension when collapsed (3 anchors). + // Layout: [margin] [bar] [max(margin, shadow)] — screen-edge side uses margin, inner side uses whichever is larger. + // When fullscreen (4 anchors), compositor ignores these. + implicitWidth: Math.ceil(barPlaceholder.barMarginH + barPlaceholder.barHeight + _innerPaddingH) + implicitHeight: Math.ceil(barPlaceholder.barMarginV + barPlaceholder.barHeight + _innerPaddingV) + // Desktop dimming when panels are open property real dimmerOpacity: Settings.data.general.dimmerOpacity ?? 0.8 property bool isPanelOpen: (PanelService.openedPanel !== null) && (PanelService.openedPanel.screen === screen) property bool isPanelClosing: (PanelService.openedPanel !== null) && PanelService.openedPanel.isClosing property bool isAnyPanelOpen: PanelService.openedPanel !== null + // Dynamic fullscreen management — collapse to bar-sized when idle to avoid fullscreen compositor damage + readonly property bool isFramed: Settings.data.bar.barType === "framed" + readonly property string _barPosition: Settings.getBarPositionForScreen(screen?.name) + readonly property bool _barIsVertical: _barPosition === "left" || _barPosition === "right" + property bool _needsFullscreen: isAnyPanelOpen || PanelService.closingPanel !== null || _dimmerAnimating + property bool _dimmerAnimating: false + + // Shadow padding for collapsed window — shadow extends beyond bar into the screen + readonly property real _shadowPadding: (Settings.data.general.enableShadows && !PowerProfileService.noctaliaPerformanceMode) ? Style.shadowBlurMax + Math.max(Math.abs(Style.shadowHorizontalOffset), Math.abs(Style.shadowVerticalOffset)) : 0 + // Inner padding: the side facing into the screen needs at least shadow clearance + readonly property real _innerPaddingH: Math.max(barPlaceholder.barMarginH, _shadowPadding) + readonly property real _innerPaddingV: Math.max(barPlaceholder.barMarginV, _shadowPadding) + color: { if (dimmerOpacity > 0 && isPanelOpen && !isPanelClosing) { return Qt.alpha(Color.mShadow, dimmerOpacity); @@ -92,6 +110,7 @@ PanelWindow { ColorAnimation { duration: isPanelClosing ? Style.animationFaster : Style.animationNormal easing.type: Easing.OutQuad + onRunningChanged: root._dimmerAnimating = running } } @@ -461,6 +480,11 @@ PanelWindow { // Expose bar dimensions directly on this Item for BarBackground // Use screen dimensions directly x: { + if (!root._needsFullscreen && !root.isFramed) { + // Collapsed: bar is at margin from screen edge, shadow extends inward. + // For right bar the window faces left (inner side first), so bar starts after shadow clearance. + return barPosition === "right" ? root._innerPaddingH : barMarginH; + } if (barPosition === "right") return (screen?.width ?? 0) - barHeight - barMarginH; if (isFramed && !barIsVertical) @@ -468,6 +492,9 @@ PanelWindow { return barMarginH; } y: { + if (!root._needsFullscreen && !root.isFramed) { + return barPosition === "bottom" ? root._innerPaddingV : barMarginV; + } if (barPosition === "bottom") return (screen?.height ?? 0) - barHeight - barMarginV; if (isFramed && barIsVertical) diff --git a/Modules/MainScreen/SmartPanel.qml b/Modules/MainScreen/SmartPanel.qml index aff4af32b..863be1c70 100644 --- a/Modules/MainScreen/SmartPanel.qml +++ b/Modules/MainScreen/SmartPanel.qml @@ -145,8 +145,10 @@ Item { // Panel visibility and sizing visible: isPanelVisible - width: parent ? parent.width : 0 - height: parent ? parent.height : 0 + // Always use screen dimensions for layout — MainScreen may be collapsed to bar-sized when idle, + // but panels must compute positions and sizes against the full screen. + width: screen?.width ?? (parent ? parent.width : 0) + height: screen?.height ?? (parent ? parent.height : 0) // Panel control functions function toggle(buttonItem, buttonName) { @@ -290,6 +292,11 @@ Item { PanelService.closedPanel(root); closed(); + // Flush pending double-buffered Wayland state (blur regions) that won't + // be committed otherwise — after an app launch the compositor may stop + // sending frame callbacks, leaving the render loop idle. + Window.window?.flushWaylandState(); + Logger.d("SmartPanel", "Panel closed immediately", objectName); } @@ -316,6 +323,9 @@ Item { PanelService.closedPanel(root); closed(); + // Flush pending double-buffered Wayland state (blur regions). + Window.window?.flushWaylandState(); + Logger.d("SmartPanel", "Panel close finalized", objectName); }