From bab166baeaebbb0d68c58fb709c4cfeed95931fb Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:09:35 +0700 Subject: [PATCH] notifications: destroy wrapper object when quickshell's notif is destroyed (#1465) --- .../common/widgets/NotificationGroup.qml | 2 +- .../common/widgets/NotificationItem.qml | 4 +- .../quickshell/ii/services/Notifications.qml | 41 ++++++++++++------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml b/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml index 22b226565..d63bbb310 100644 --- a/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml +++ b/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml @@ -53,7 +53,7 @@ Item { // Notification group area onFinished: () => { root.notifications.forEach((notif) => { Qt.callLater(() => { - Notifications.discardNotification(notif.id); + Notifications.discardNotification(notif.notificationId); }); }); } diff --git a/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml b/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml index 4b97d3daa..4f5688b83 100644 --- a/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml +++ b/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml @@ -70,7 +70,7 @@ Item { // Notification item area easing.bezierCurve: Appearance.animation.elementMove.bezierCurve } onFinished: () => { - Notifications.discardNotification(notificationObject.id); + Notifications.discardNotification(notificationObject.notificationId); } } @@ -269,7 +269,7 @@ Item { // Notification item area buttonText: modelData.text urgency: notificationObject.urgency onClicked: { - Notifications.attemptInvokeAction(notificationObject.id, modelData.identifier); + Notifications.attemptInvokeAction(notificationObject.notificationId, modelData.identifier); } } } diff --git a/.config/quickshell/ii/services/Notifications.qml b/.config/quickshell/ii/services/Notifications.qml index d0d51e8ef..0c4e776d0 100644 --- a/.config/quickshell/ii/services/Notifications.qml +++ b/.config/quickshell/ii/services/Notifications.qml @@ -17,7 +17,8 @@ import Quickshell.Services.Notifications Singleton { id: root component Notif: QtObject { - required property int id + id: wrapper + required property int notificationId // Could just be `id` but it conflicts with the default prop in QtObject property Notification notification property list actions: notification?.actions.map((action) => ({ "identifier": action.identifier, @@ -32,11 +33,19 @@ Singleton { property double time property string urgency: notification?.urgency.toString() ?? "normal" property Timer timer + + readonly property Connections conn: Connections { + target: wrapper.notification.Component + + function onDestruction(): void { + wrapper.destroy(); + } + } } function notifToJSON(notif) { return { - "id": notif.id, + "notificationId": notif.notificationId, "actions": notif.actions, "appIcon": notif.appIcon, "appName": notif.appName, @@ -52,11 +61,11 @@ Singleton { } component NotifTimer: Timer { - required property int id + required property int notificationId interval: 5000 running: true onTriggered: () => { - root.timeoutNotification(id); + root.timeoutNotification(notificationId); destroy() } } @@ -130,7 +139,7 @@ Singleton { property int idOffset signal initDone(); signal notify(notification: var); - signal discard(id: var); + signal discard(id: int); signal discardAll(); signal timeout(id: var); @@ -149,7 +158,7 @@ Singleton { onNotification: (notification) => { notification.tracked = true const newNotifObject = notifComponent.createObject(root, { - "id": notification.id + root.idOffset, + "notificationId": notification.id + root.idOffset, "notification": notification, "time": Date.now(), }); @@ -159,7 +168,7 @@ Singleton { if (!root.popupInhibited) { newNotifObject.popup = true; newNotifObject.timer = notifTimerComponent.createObject(root, { - "id": newNotifObject.id, + "notificationId": newNotifObject.notificationId, "interval": notification.expireTimeout < 0 ? 5000 : notification.expireTimeout, }); } @@ -171,7 +180,8 @@ Singleton { } function discardNotification(id) { - const index = root.list.findIndex((notif) => notif.id === id); + console.log("[Notifications] Discarding notification with ID: " + id); + const index = root.list.findIndex((notif) => notif.notificationId === id); const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id); if (index !== -1) { root.list.splice(index, 1); @@ -181,7 +191,7 @@ Singleton { if (notifServerIndex !== -1) { notifServer.trackedNotifications.values[notifServerIndex].dismiss() } - root.discard(id); + root.discard(id); // Emit signal } function discardAllNotifications() { @@ -195,7 +205,7 @@ Singleton { } function timeoutNotification(id) { - const index = root.list.findIndex((notif) => notif.id === id); + const index = root.list.findIndex((notif) => notif.notificationId === id); if (root.list[index] != null) root.list[index].popup = false; root.timeout(id); @@ -203,7 +213,7 @@ Singleton { function timeoutAll() { root.popupList.forEach((notif) => { - root.timeout(notif.id); + root.timeout(notif.notificationId); }) root.popupList.forEach((notif) => { notif.popup = false; @@ -211,10 +221,13 @@ Singleton { } function attemptInvokeAction(id, notifIdentifier) { + console.log("[Notifications] Attempting to invoke action with identifier: " + notifIdentifier + " for notification ID: " + id); const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id); + console.log("Notification server index: " + notifServerIndex); if (notifServerIndex !== -1) { const notifServerNotif = notifServer.trackedNotifications.values[notifServerIndex]; const action = notifServerNotif.actions.find((action) => action.identifier === notifIdentifier); + console.log("Action found: " + JSON.stringify(action)); action.invoke() } else { @@ -242,7 +255,7 @@ Singleton { const fileContents = notifFileView.text() root.list = JSON.parse(fileContents).map((notif) => { return notifComponent.createObject(root, { - "id": notif.id, + "notificationId": notif.notificationId, "actions": [], // Notification actions are meaningless if they're not tracked by the server or the sender is dead "appIcon": notif.appIcon, "appName": notif.appName, @@ -253,10 +266,10 @@ Singleton { "urgency": notif.urgency, }); }); - // Find largest id + // Find largest notificationId let maxId = 0 root.list.forEach((notif) => { - maxId = Math.max(maxId, notif.id) + maxId = Math.max(maxId, notif.notificationId) }) console.log("[Notifications] File loaded")