diff --git a/quickshell/Modules/Notifications/NotificationCard.qml b/quickshell/Modules/Notifications/NotificationCard.qml index e68514837..7580ebbda 100644 --- a/quickshell/Modules/Notifications/NotificationCard.qml +++ b/quickshell/Modules/Notifications/NotificationCard.qml @@ -55,7 +55,7 @@ Rectangle { function saveDisplayImage() { const data = root.notificationData; - if (!root.persistImage || !data?.hasDisplayImage || data.persistedImagePath) + if (!root.persistImage || !data?.notification || !data.hasDisplayImage || data.persistedImagePath) return; const image = data.image || ""; if (!image.startsWith("image://qsimage/") && !NotificationService.notificationIconFromImage(image).startsWith("/")) diff --git a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml index 84a300326..f631fa296 100644 --- a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml +++ b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml @@ -61,6 +61,7 @@ PanelWindow { readonly property bool cardShown: presenting && (presentationProgress > 0 || !exiting) readonly property bool layoutPinned: !exiting && (hovered || contextMenuActive || swipeActive) property bool exiting: false + property var exitSnapshot: null property bool exitStarted: false property bool collapseChromeOnExit: false property bool _isDestroying: false @@ -124,6 +125,7 @@ PanelWindow { } enterAnimation.stop(); enterDelay.stop(); + exitSnapshot = snapshotNotification(notificationData); exiting = true; if (NotificationService.removeFromVisibleNotifications) NotificationService.removeFromVisibleNotifications(win.notificationData); @@ -172,6 +174,29 @@ PanelWindow { win.exitFinished(); } + // The wrapper is destroyed as soon as its notification closes, which would blank the card mid-exit. + function snapshotNotification(data) { + if (!data) + return null; + return { + "appName": data.appName, + "appIcon": data.appIcon, + "desktopEntry": data.desktopEntry, + "summary": data.summary, + "body": data.body, + "htmlBody": data.htmlBody, + "image": data.image, + "hasDisplayImage": data.hasDisplayImage, + "displayImage": data.displayImage, + "persistedImagePath": data.persistedImagePath, + "timeStr": data.timeStr, + "urgency": data.urgency, + "actions": Array.from(data.actions || [], action => ({ + "text": action.text + })) + }; + } + function closeTransientUi() { transientSurfaces.closeAll(); popupContextMenuLoader.active = false; @@ -719,7 +744,7 @@ PanelWindow { chipColor: Theme.notificationChipSurface width: parent.width height: win.inlineHeightAnimating ? Math.min(targetHeight, cardSurface.height - win.timeoutRailClearance) : targetHeight - notificationData: win.notificationData + notificationData: win.exitSnapshot ?? win.notificationData descriptionExpanded: win.descriptionExpanded privacyMode: SettingsData.notificationPopupPrivacyMode bodyInvokesAction: win.bodyClickInvokesAction