From c8d8709c26f316bfc5ad1cae048e18007496a36f Mon Sep 17 00:00:00 2001 From: Lemmy Date: Fri, 20 Mar 2026 00:29:04 -0400 Subject: [PATCH] Revert "perf(mainscreen): merging fix/damage-control" This reverts commit 67a7f75c37eaa384bb2aa910d104ddb56bd2f9ae, reversing changes made to 8828d9d7be9e9a4e8d07251affbbfa5324bd0527. --- Modules/Bar/Extras/BarExclusionZone.qml | 1 + Modules/Dock/Dock.qml | 1 + Modules/MainScreen/AllScreens.qml | 14 -- Modules/MainScreen/BarContentWindow.qml | 1 + Modules/MainScreen/BarExclusionZone.qml | 1 + Modules/MainScreen/BarTriggerZone.qml | 1 + Modules/MainScreen/MainScreen.qml | 42 +--- Modules/MainScreen/ScreenCornerWindow.qml | 87 -------- Modules/MainScreen/ScreenCorners.qml | 231 ++++++++++++++++++++++ Modules/MainScreen/SmartPanel.qml | 14 +- Services/UI/PanelService.qml | 9 - 11 files changed, 248 insertions(+), 154 deletions(-) delete mode 100644 Modules/MainScreen/ScreenCornerWindow.qml create mode 100644 Modules/MainScreen/ScreenCorners.qml diff --git a/Modules/Bar/Extras/BarExclusionZone.qml b/Modules/Bar/Extras/BarExclusionZone.qml index 1e7a9a01d..f5333b43d 100644 --- a/Modules/Bar/Extras/BarExclusionZone.qml +++ b/Modules/Bar/Extras/BarExclusionZone.qml @@ -25,6 +25,7 @@ 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/Dock/Dock.qml b/Modules/Dock/Dock.qml index 303b2457f..62502b32c 100644 --- a/Modules/Dock/Dock.qml +++ b/Modules/Dock/Dock.qml @@ -774,6 +774,7 @@ 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/AllScreens.qml b/Modules/MainScreen/AllScreens.qml index c2a78ad41..2039dd010 100644 --- a/Modules/MainScreen/AllScreens.qml +++ b/Modules/MainScreen/AllScreens.qml @@ -103,20 +103,6 @@ Variants { } } - // Screen corners - 4 small PanelWindows, one per corner - Repeater { - model: ["topLeft", "topRight", "bottomLeft", "bottomRight"] - delegate: Loader { - active: windowItem.windowLoaded && windowItem.shouldBeActive - asynchronous: false - - sourceComponent: ScreenCornerWindow { - screen: windowItem.modelData - corner: modelData - } - } - } - // BarExclusionZone - created after MainScreen has fully loaded // Note: Exclusion zone should NOT be affected by hideOnOverview setting. // When bar is hidden during overview, the exclusion zone should remain to prevent diff --git a/Modules/MainScreen/BarContentWindow.qml b/Modules/MainScreen/BarContentWindow.qml index 3e5da24b2..562cb1895 100644 --- a/Modules/MainScreen/BarContentWindow.qml +++ b/Modules/MainScreen/BarContentWindow.qml @@ -33,6 +33,7 @@ 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 db97fd8af..e9696e62e 100644 --- a/Modules/MainScreen/BarExclusionZone.qml +++ b/Modules/MainScreen/BarExclusionZone.qml @@ -37,6 +37,7 @@ 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 ae0538e20..b7a9cd58b 100644 --- a/Modules/MainScreen/BarTriggerZone.qml +++ b/Modules/MainScreen/BarTriggerZone.qml @@ -26,6 +26,7 @@ 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 6c686c465..712e4f25e 100644 --- a/Modules/MainScreen/MainScreen.qml +++ b/Modules/MainScreen/MainScreen.qml @@ -44,6 +44,9 @@ PanelWindow { } // Wayland + // As this is always rendered, putting it on the top layer + // would prevent direct scanout for other Wayland clients. + // WlrLayershell.layer: WlrLayer.Top WlrLayershell.namespace: "noctalia-background-" + (screen?.name || "unknown") WlrLayershell.exclusionMode: ExclusionMode.Ignore // Don't reserve space - BarExclusionZone handles that WlrLayershell.keyboardFocus: { @@ -67,37 +70,18 @@ PanelWindow { } anchors { - top: isFramed || _needsFullscreen || _barPosition !== "bottom" - bottom: isFramed || _needsFullscreen || _barPosition !== "top" - left: isFramed || _needsFullscreen || _barPosition !== "right" - right: isFramed || _needsFullscreen || _barPosition !== "left" + top: true + bottom: true + left: true + right: true } - // 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); @@ -110,7 +94,6 @@ PanelWindow { ColorAnimation { duration: isPanelClosing ? Style.animationFaster : Style.animationNormal easing.type: Easing.OutQuad - onRunningChanged: root._dimmerAnimating = running } } @@ -480,11 +463,6 @@ 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) @@ -492,9 +470,6 @@ 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) @@ -572,6 +547,9 @@ PanelWindow { } } + // Screen Corners + ScreenCorners {} + // Blur behind the bar and open panels // Helper object holding computed properties for blur regions QtObject { diff --git a/Modules/MainScreen/ScreenCornerWindow.qml b/Modules/MainScreen/ScreenCornerWindow.qml deleted file mode 100644 index e33ce5ebb..000000000 --- a/Modules/MainScreen/ScreenCornerWindow.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import QtQuick.Shapes -import Quickshell -import Quickshell.Wayland -import qs.Commons - -/** -* ScreenCornerWindow - Small PanelWindow that renders a single concave screen corner. -*/ -PanelWindow { - id: root - - required property string corner // "topLeft", "topRight", "bottomLeft", "bottomRight" - - readonly property real s: Style.screenRadius - readonly property bool shouldShow: Settings.data.general.showScreenCorners && s > 0 - - visible: shouldShow - color: "transparent" - - // Click-through - mask: Region {} - - WlrLayershell.namespace: "noctalia-corner-" + corner + "-" + (screen?.name || "unknown") - WlrLayershell.exclusionMode: ExclusionMode.Ignore - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - anchors { - top: corner === "topLeft" || corner === "topRight" - bottom: corner === "bottomLeft" || corner === "bottomRight" - left: corner === "topLeft" || corner === "bottomLeft" - right: corner === "topRight" || corner === "bottomRight" - } - - implicitWidth: Math.ceil(s) - implicitHeight: Math.ceil(s) - - // Cache to texture to avoid continuous re-tessellation - Item { - anchors.fill: parent - layer.enabled: true - - Shape { - anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - asynchronous: true - enabled: false - visible: root.s > 0 && width > 0 && height > 0 - - ShapePath { - id: cornerPath - - readonly property color cornerColor: Settings.data.general.forceBlackScreenCorners ? "black" : Color.mSurface - - strokeWidth: -1 - fillColor: root.shouldShow ? cornerColor : "transparent" - - Behavior on fillColor { - enabled: !Color.isTransitioning - ColorAnimation { - duration: Style.animationFast - } - } - - PathSvg { - path: { - var s = root.s; - if (s <= 0) - return "M -1 -1 L -1 0 L 0 0 Z"; - switch (root.corner) { - case "topLeft": - return "M 0 0 L " + s + " 0 A " + s + " " + s + " 0 0 0 0 " + s + " Z"; - case "topRight": - return "M 0 0 L " + s + " 0 L " + s + " " + s + " A " + s + " " + s + " 0 0 0 0 0 Z"; - case "bottomLeft": - return "M 0 0 A " + s + " " + s + " 0 0 0 " + s + " " + s + " L 0 " + s + " Z"; - case "bottomRight": - return "M " + s + " " + s + " L 0 " + s + " A " + s + " " + s + " 0 0 0 " + s + " 0 Z"; - default: - return "M -1 -1 L -1 0 L 0 0 Z"; - } - } - } - } - } - } -} diff --git a/Modules/MainScreen/ScreenCorners.qml b/Modules/MainScreen/ScreenCorners.qml new file mode 100644 index 000000000..4387ecfa1 --- /dev/null +++ b/Modules/MainScreen/ScreenCorners.qml @@ -0,0 +1,231 @@ +import QtQuick +import QtQuick.Shapes +import qs.Commons + +/** +* ScreenCorners - Shape component for rendering screen corners +* +* Renders concave corners at the screen edges to create a rounded screen effect. +* Self-contained Shape component (no shadows). +*/ +Item { + id: root + + anchors.fill: parent + + // Wrapper with layer caching to reduce GPU tessellation overhead + Item { + anchors.fill: parent + + // Cache the Shape to a texture to prevent continuous re-tessellation + layer.enabled: true + + Shape { + id: cornersShape + + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + asynchronous: true + enabled: false // Disable mouse input + visible: cornersPath.cornerRadius > 0 && width > 0 && height > 0 + + ShapePath { + id: cornersPath + + // Corner configuration + readonly property color cornerColor: Settings.data.general.forceBlackScreenCorners ? "black" : Color.mSurface + readonly property real cornerRadius: Style.screenRadius + readonly property real cornerSize: Style.screenRadius + + // Determine margins based on bar position + readonly property real topMargin: 0 + readonly property real bottomMargin: 0 + readonly property real leftMargin: 0 + readonly property real rightMargin: 0 + + // Screen dimensions + readonly property real screenWidth: cornersShape.width + readonly property real screenHeight: cornersShape.height + + // Only show screen corners if enabled and appropriate conditions are met + readonly property bool shouldShow: Settings.data.general.showScreenCorners + + // ShapePath configuration + strokeWidth: -1 // No stroke, fill only + fillColor: shouldShow ? cornerColor : "transparent" + + // Smooth color animation (disabled during theme transitions to sync with Color.qml) + Behavior on fillColor { + enabled: !Color.isTransitioning + ColorAnimation { + duration: Style.animationFast + } + } + + // ========== PATH DEFINITION ========== + // Draws 4 separate corner squares at screen edges + // Each corner square has a concave arc on the inner diagonal + + // ========== TOP-LEFT CORNER ========== + // Arc is at the bottom-right of this square (inner diagonal) + // Start at top-left screen corner + startX: leftMargin + startY: topMargin + + // Top edge (moving right) + PathLine { + relativeX: cornersPath.cornerSize + relativeY: 0 + } + + // Right edge (moving down toward arc) + PathLine { + relativeX: 0 + relativeY: cornersPath.cornerSize - cornersPath.cornerRadius + } + + // Concave arc (bottom-right corner of square, curving inward toward screen center) + PathArc { + relativeX: -cornersPath.cornerRadius + relativeY: cornersPath.cornerRadius + radiusX: cornersPath.cornerRadius + radiusY: cornersPath.cornerRadius + direction: PathArc.Counterclockwise + } + + // Bottom edge (moving left) + PathLine { + relativeX: -(cornersPath.cornerSize - cornersPath.cornerRadius) + relativeY: 0 + } + + // Left edge (moving up) - closes back to start + PathLine { + relativeX: 0 + relativeY: -cornersPath.cornerSize + } + + // ========== TOP-RIGHT CORNER ========== + // Arc is at the bottom-left of this square (inner diagonal) + PathMove { + x: cornersPath.screenWidth - cornersPath.rightMargin - cornersPath.cornerSize + y: cornersPath.topMargin + } + + // Top edge (moving right) + PathLine { + relativeX: cornersPath.cornerSize + relativeY: 0 + } + + // Right edge (moving down) + PathLine { + relativeX: 0 + relativeY: cornersPath.cornerSize + } + + // Bottom edge (moving left toward arc) + PathLine { + relativeX: -(cornersPath.cornerSize - cornersPath.cornerRadius) + relativeY: 0 + } + + // Concave arc (bottom-left corner of square, curving inward toward screen center) + PathArc { + relativeX: -cornersPath.cornerRadius + relativeY: -cornersPath.cornerRadius + radiusX: cornersPath.cornerRadius + radiusY: cornersPath.cornerRadius + direction: PathArc.Counterclockwise + } + + // Left edge (moving up) - closes back to start + PathLine { + relativeX: 0 + relativeY: -(cornersPath.cornerSize - cornersPath.cornerRadius) + } + + // ========== BOTTOM-LEFT CORNER ========== + // Arc is at the top-right of this square (inner diagonal) + PathMove { + x: cornersPath.leftMargin + y: cornersPath.screenHeight - cornersPath.bottomMargin - cornersPath.cornerSize + } + + // Top edge (moving right toward arc) + PathLine { + relativeX: cornersPath.cornerSize - cornersPath.cornerRadius + relativeY: 0 + } + + // Concave arc (top-right corner of square, curving inward toward screen center) + PathArc { + relativeX: cornersPath.cornerRadius + relativeY: cornersPath.cornerRadius + radiusX: cornersPath.cornerRadius + radiusY: cornersPath.cornerRadius + direction: PathArc.Counterclockwise + } + + // Right edge (moving down) + PathLine { + relativeX: 0 + relativeY: cornersPath.cornerSize - cornersPath.cornerRadius + } + + // Bottom edge (moving left) + PathLine { + relativeX: -cornersPath.cornerSize + relativeY: 0 + } + + // Left edge (moving up) - closes back to start + PathLine { + relativeX: 0 + relativeY: -cornersPath.cornerSize + } + + // ========== BOTTOM-RIGHT CORNER ========== + // Arc is at the top-left of this square (inner diagonal) + // Start at bottom-right of square (different from other corners!) + PathMove { + x: cornersPath.screenWidth - cornersPath.rightMargin + y: cornersPath.screenHeight - cornersPath.bottomMargin + } + + // Bottom edge (moving left) + PathLine { + relativeX: -cornersPath.cornerSize + relativeY: 0 + } + + // Left edge (moving up toward arc) + PathLine { + relativeX: 0 + relativeY: -(cornersPath.cornerSize - cornersPath.cornerRadius) + } + + // Concave arc (top-left corner of square, curving inward toward screen center) + PathArc { + relativeX: cornersPath.cornerRadius + relativeY: -cornersPath.cornerRadius + radiusX: cornersPath.cornerRadius + radiusY: cornersPath.cornerRadius + direction: PathArc.Counterclockwise + } + + // Top edge (moving right) + PathLine { + relativeX: cornersPath.cornerSize - cornersPath.cornerRadius + relativeY: 0 + } + + // Right edge (moving down) - closes back to start + PathLine { + relativeX: 0 + relativeY: cornersPath.cornerSize + } + } + } + } +} diff --git a/Modules/MainScreen/SmartPanel.qml b/Modules/MainScreen/SmartPanel.qml index 0653a958b..bc704198c 100644 --- a/Modules/MainScreen/SmartPanel.qml +++ b/Modules/MainScreen/SmartPanel.qml @@ -145,10 +145,8 @@ Item { // Panel visibility and sizing visible: isPanelVisible - // 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) + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 // Panel control functions function toggle(buttonItem, buttonName) { @@ -292,11 +290,6 @@ 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); } @@ -323,9 +316,6 @@ Item { PanelService.closedPanel(root); closed(); - // Flush pending double-buffered Wayland state (blur regions). - Window.window?.flushWaylandState(); - Logger.d("SmartPanel", "Panel close finalized", objectName); } diff --git a/Services/UI/PanelService.qml b/Services/UI/PanelService.qml index 825a557b8..89993f94b 100644 --- a/Services/UI/PanelService.qml +++ b/Services/UI/PanelService.qml @@ -399,15 +399,6 @@ Singleton { assignToSlot(1, null); } - // Reset closedImmediately after the current event cycle so all Behaviors - // that check it have processed their snaps. Cannot rely on MainScreen's - // onColorChanged because the color may already be transparent (dimmerOpacity=0). - if (closedImmediately) { - Qt.callLater(() => { - closedImmediately = false; - }); - } - // Reset keyboard init state isInitializingKeyboard = false; keyboardInitTimer.stop();