From accdd0972cadaedd1aab99cccc54a30a7474049b Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 21 Jul 2026 17:45:54 -0400 Subject: [PATCH] popout: fix lifecycle of blur with various popouts fixes #2901 port 1.5 (cherry picked from commit 93c3030a1e1553bf6ea63a3dde816dffc09e1237) --- quickshell/Common/PopoutManager.qml | 23 +++++++++++++++++-- .../ControlCenter/ControlCenterPopout.qml | 6 +++++ .../DankBar/Widgets/ClipboardButton.qml | 4 ++-- .../Center/NotificationCenterPopout.qml | 5 ++++ quickshell/Widgets/DankPopoutStandalone.qml | 17 +++++++------- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/quickshell/Common/PopoutManager.qml b/quickshell/Common/PopoutManager.qml index f7e49befa..a3729f7fe 100644 --- a/quickshell/Common/PopoutManager.qml +++ b/quickshell/Common/PopoutManager.qml @@ -65,16 +65,35 @@ Singleton { function _openPopout(popout) { if (popout.dashVisible !== undefined) { - if (popout.dashVisible && !popout.shouldBeVisible && !popout.isClosing) + let flagStayedTrue = popout.dashVisible === true; + if (popout.dashVisible && !popout.shouldBeVisible && !popout.isClosing) { popout.dashVisible = false; + flagStayedTrue = false; + } popout.dashVisible = true; + // Flag already true (e.g. retargeting to another monitor) won't re-fire + // the change handler, so drive the surface open explicitly. + if (flagStayedTrue) + _ensureSurfaceOpen(popout); return; } if (popout.notificationHistoryVisible !== undefined) { + const flagStayedTrue = popout.notificationHistoryVisible === true; popout.notificationHistoryVisible = true; + if (flagStayedTrue) + _ensureSurfaceOpen(popout); return; } - popout.open(); + _ensureSurfaceOpen(popout); + } + + function _ensureSurfaceOpen(popout) { + if (typeof popout.present === "function") { + popout.present(); + return; + } + if (typeof popout.open === "function") + popout.open(); } function _closePopout(popout) { diff --git a/quickshell/Modules/ControlCenter/ControlCenterPopout.qml b/quickshell/Modules/ControlCenter/ControlCenterPopout.qml index ffc732bdf..c2e6e79cb 100644 --- a/quickshell/Modules/ControlCenter/ControlCenterPopout.qml +++ b/quickshell/Modules/ControlCenter/ControlCenterPopout.qml @@ -77,6 +77,12 @@ DankPopout { readonly property color _containerBg: Theme.nestedSurface + // Defer open one tick so screen-change geometry settles before the surface + // maps; a synchronous open churns the surface and loses the blur on a switch. + function present() { + Qt.callLater(open); + } + function openWithSection(section) { StateUtils.openWithSection(root, section); } diff --git a/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml b/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml index 0e535a90d..7de97fcfd 100644 --- a/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml +++ b/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml @@ -63,8 +63,8 @@ BasePill { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton cursorShape: Qt.PointingHandCursor - onPressed: mouse => root.triggerRipple(this, mouse.x, mouse.y) - onClicked: function (mouse) { + onPressed: function (mouse) { + root.triggerRipple(this, mouse.x, mouse.y); switch (mouse.button) { case Qt.RightButton: openContextMenu(); diff --git a/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml b/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml index a87dcbeef..12aa14506 100644 --- a/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml +++ b/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml @@ -61,6 +61,11 @@ DankPopout { notificationHistoryVisible = !notificationHistoryVisible; } + // Re-open without toggling the flag (used when retargeting to another monitor). + function present() { + openSized(); + } + function openSized() { if (!notificationHistoryVisible) return; diff --git a/quickshell/Widgets/DankPopoutStandalone.qml b/quickshell/Widgets/DankPopoutStandalone.qml index ff88ae30a..a4e84cc9c 100644 --- a/quickshell/Widgets/DankPopoutStandalone.qml +++ b/quickshell/Widgets/DankPopoutStandalone.qml @@ -79,6 +79,9 @@ Item { "rightBar": 0 }) property var screen: null + // Output the surface binds to; retargeted only in open() while hidden. A live + // screen change on a mapped surface loses the popup blur on niri. + property var surfaceScreen: null readonly property bool frameGapStandaloneActive: CompositorService.frameConfiguredForScreen(screen) && !CompositorService.usesConnectedFrameChromeForScreen(screen) readonly property bool fluidStandaloneActive: Theme.isDirectionalEffect readonly property bool backgroundDismissWindowRequired: backgroundInteractive @@ -133,8 +136,6 @@ Item { signal popoutClosed signal backgroundClicked - property var _lastOpenedScreen: null - property int effectiveBarPosition: 0 property real effectiveBarBottomGap: 0 readonly property string autoBarShadowDirection: { @@ -338,14 +339,14 @@ Item { _frozenMaskWidth = maskWidth; _frozenMaskHeight = maskHeight; - const screenChanged = _lastOpenedScreen !== null && _lastOpenedScreen !== screen; + const screenChanged = surfaceScreen !== null && surfaceScreen !== screen; if (screenChanged) { - // Hide on this tick so Qt actually tears down the wl_surface; the show - // gets deferred below so the unmap is processed before the remap. + // Unmap before retargeting so the surface is destroyed and recreated + // on the new output rather than live-migrated. contentWindow.visible = false; backgroundWindow.visible = false; } - _lastOpenedScreen = screen; + surfaceScreen = screen; if (contentContainer && !shouldBeVisible) { // Snap morph closed only on a fresh open; on screen-change re-open we stay at 1 @@ -559,7 +560,7 @@ Item { PanelWindow { id: backgroundWindow - screen: root.screen + screen: root.surfaceScreen visible: false color: "transparent" // Skip buffer updates when there's nothing to render. Briefly flipped @@ -625,7 +626,7 @@ Item { PanelWindow { id: contentWindow - screen: root.screen + screen: root.surfaceScreen visible: false color: "transparent" readonly property bool closeVisualActive: root.shouldBeVisible || root.isClosing