notifications: destroy wrapper object when quickshell's notif is destroyed (#1465)

This commit is contained in:
end-4
2025-07-18 16:09:35 +07:00
parent 40f2e0b6a7
commit bab166baea
3 changed files with 30 additions and 17 deletions
@@ -53,7 +53,7 @@ Item { // Notification group area
onFinished: () => {
root.notifications.forEach((notif) => {
Qt.callLater(() => {
Notifications.discardNotification(notif.id);
Notifications.discardNotification(notif.notificationId);
});
});
}
@@ -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);
}
}
}
@@ -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<var> 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")