diff --git a/urgent-on-notification/Main.qml b/urgent-on-notification/Main.qml new file mode 100644 index 000000000..c2b4614bc --- /dev/null +++ b/urgent-on-notification/Main.qml @@ -0,0 +1,98 @@ +import QtQuick +import Quickshell.Io +import Quickshell.Services.Notifications + +import qs.Services.System + +Item { + id: root + property var pluginApi: null + + property var trackedNotifs: [] + + property var niriWindowListProcess: Component { + Process { + property string appEntry: "" + property bool unset: false + + command: ["niri", "msg", "--json", "windows"] + + stdout: SplitParser { + onRead: data => { + try { + const windows = JSON.parse(data); + const matches = windows.filter(w => w.app_id && w.app_id.toLowerCase() === appEntry || w.app_id.includes(appEntry) || appEntry.includes(w.app_id)); + if (matches.length > 0) { + matches.forEach(m => { + niriUrgentProcess.createObject(root, { + windowId: m.id, + unset: unset + }).running = true; + }); + } + } catch (e) {} + destroy(); + } + } + } + } + + property var niriUrgentProcess: Component { + Process { + property int windowId: 0 + property bool unset: false + command: ["niri", "msg", "action", unset ? "unset-window-urgent" : "set-window-urgent", "--id", String(windowId)] + onExited: destroy() + } + } + + property var server: NotificationServer { + keepOnReload: false + imageSupported: true + actionsSupported: true + + onNotification: notification => { + const entry = (notification.desktopEntry || notification.appName || "").toLowerCase(); + if (!entry) + return; + trackedNotifs = [...trackedNotifs, + { + id: notification.id, + entry: entry + } + ]; + niriWindowListProcess.createObject(root, { + appEntry: entry.toLowerCase() + }).running = true; + } + } + + property var historyWatcher: Connections { + target: NotificationService.historyModel + + function onCountChanged() { + const model = NotificationService.historyModel; + + const currentIds = new Set(); + for (let i = 0; i < model.count; i++) { + const n = model.get(i); + currentIds.add(n.originalId); + } + + const removedNotifs = trackedNotifs.filter(n => !currentIds.has(n.id)); + const remainingNotifs = trackedNotifs.filter(n => currentIds.has(n.id)); + + for (const n of removedNotifs) { + const appHasMultipleNotifs = remainingNotifs.some(r => r.entry === n.entry); + if (!appHasMultipleNotifs) { + niriWindowListProcess.createObject(root, { + appEntry: n.entry.toLowerCase(), + unset: true + }).running = true; + } + } + + trackedNotifs = remainingNotifs; + } + } +} diff --git a/urgent-on-notification/README.md b/urgent-on-notification/README.md new file mode 100644 index 000000000..8f052fe45 --- /dev/null +++ b/urgent-on-notification/README.md @@ -0,0 +1,20 @@ +# Set Urgent Window on Notification + +This plugin captures notifications and sets the related window's urgent status on Niri. +Useful for having urgent borders on multi-monitor setups. + +--- + +## Features + +* Set window to urgent on notification received +* If multiple windows exist for the same app, all of them are set to urgent +* Unset urgent status when all notifications are cleared for an app +* Some leniency when matching based on app ID + +--- + +## Requirements + +* Niri +* Usage of Noctalia's notification history diff --git a/urgent-on-notification/manifest.json b/urgent-on-notification/manifest.json new file mode 100644 index 000000000..8c4f64e2d --- /dev/null +++ b/urgent-on-notification/manifest.json @@ -0,0 +1,24 @@ +{ + "id": "urgent-on-notification", + "name": "Set Window to Urgent on Notification", + "version": "1.0.0", + "minNoctaliaVersion": "3.6.0", + "author": "matt-hb", + "tags": [ + "System", + "Utility", + "Niri" + ], + "license": "MIT", + "repository": "https://github.com/noctalia-dev/noctalia-plugins", + "description": "Sets windows to urgent when they receive a notification and sets them back to normal when their notifications are cleared", + "entryPoints": { + "main": "Main.qml" + }, + "dependencies": { + "plugins": [] + }, + "metadata": { + "defaultSettings": {} + } +} diff --git a/urgent-on-notification/preview.png b/urgent-on-notification/preview.png new file mode 100644 index 000000000..4e27bfcc6 Binary files /dev/null and b/urgent-on-notification/preview.png differ