summaryrefslogtreecommitdiffstats
path: root/home-configuration/config
diff options
context:
space:
mode:
Diffstat (limited to 'home-configuration/config')
-rw-r--r--home-configuration/config/niri/config.kdl2
-rw-r--r--home-configuration/config/quickshell/modules/notifications/NotificationFocus.qml228
2 files changed, 173 insertions, 57 deletions
diff --git a/home-configuration/config/niri/config.kdl b/home-configuration/config/niri/config.kdl
index e8fe85c..06aea17 100644
--- a/home-configuration/config/niri/config.kdl
+++ b/home-configuration/config/niri/config.kdl
@@ -1,5 +1,5 @@
spawn-sh-at-startup "XDG_DATA_DIRS=/etc/profiles/per-user/coast/share:/run/current-system/sw/share:$HOME/.nix-profile/share:$XDG_DATA_DIRS"
-spawn-at-startup "quickshell -c ~/.config/quickshell"
+spawn-at-startup "qs"
spawn-at-startup "dbus-update-activation-environment" "--systemd" "WAYLAND_DISPLAY" "XDG_CURRENT_DESKTOP"
input {
diff --git a/home-configuration/config/quickshell/modules/notifications/NotificationFocus.qml b/home-configuration/config/quickshell/modules/notifications/NotificationFocus.qml
index af52eaa..ce59b2a 100644
--- a/home-configuration/config/quickshell/modules/notifications/NotificationFocus.qml
+++ b/home-configuration/config/quickshell/modules/notifications/NotificationFocus.qml
@@ -1,13 +1,120 @@
import QtQuick
import Quickshell
import Quickshell.Io
-import "../../config.js" as Config
Item {
id: root
property string pendingApp: ""
+ function normalize(value) {
+ if (!value)
+ return ""
+
+ var result = String(value).toLowerCase().trim()
+
+ result = result.replace(/^org\./, "")
+ result = result.replace(/^com\./, "")
+ result = result.replace(/^net\./, "")
+ result = result.replace(/^app\./, "")
+
+ result = result.replace(/\.desktop$/, "")
+ result = result.replace(/\.desktop$/i, "")
+
+ result = result.replace(/[^a-z0-9]+/g, "")
+
+ return result
+ }
+
+ function candidates(value) {
+ var result = []
+ var raw = String(value || "").toLowerCase().trim()
+
+ function add(candidate) {
+ if (!candidate)
+ return
+
+ candidate = normalize(candidate)
+
+ if (candidate && result.indexOf(candidate) === -1)
+ result.push(candidate)
+ }
+
+ add(raw)
+
+ if (raw.indexOf(".") !== -1) {
+ var parts = raw.split(".")
+
+ add(parts[parts.length - 1])
+
+ for (var i = 0; i < parts.length; i++)
+ add(parts[i])
+ }
+
+ if (raw.indexOf("/") !== -1)
+ add(raw.split("/").pop())
+
+ if (raw.indexOf("-") !== -1) {
+ var dashParts = raw.split("-")
+
+ for (var j = 0; j < dashParts.length; j++)
+ add(dashParts[j])
+ }
+
+ if (raw.indexOf("_") !== -1) {
+ var underscoreParts = raw.split("_")
+
+ for (var k = 0; k < underscoreParts.length; k++)
+ add(underscoreParts[k])
+ }
+
+ return result
+ }
+
+ function matchScore(notificationApp, windowAppId, windowTitle) {
+ var notificationCandidates = candidates(notificationApp)
+ var windowCandidates = candidates(windowAppId)
+
+ var best = 0
+
+ for (var i = 0; i < notificationCandidates.length; i++) {
+ var notificationCandidate = notificationCandidates[i]
+
+ for (var j = 0; j < windowCandidates.length; j++) {
+ var windowCandidate = windowCandidates[j]
+
+ if (notificationCandidate === windowCandidate)
+ best = Math.max(best, 100)
+
+ else if (
+ notificationCandidate.length >= 4 &&
+ windowCandidate.length >= 4 &&
+ (
+ notificationCandidate.indexOf(windowCandidate) !== -1 ||
+ windowCandidate.indexOf(notificationCandidate) !== -1
+ )
+ ) {
+ best = Math.max(best, 60)
+ }
+ }
+ }
+
+ var titleCandidates = candidates(windowTitle)
+
+ for (var n = 0; n < notificationCandidates.length; n++) {
+ for (var t = 0; t < titleCandidates.length; t++) {
+ if (
+ notificationCandidates[n].length >= 4 &&
+ notificationCandidates[n] === titleCandidates[t]
+ ) {
+ best = Math.max(best, 30)
+ }
+ }
+ }
+
+ return best
+ }
+
Process {
id: windowsProcess
@@ -23,7 +130,7 @@ Item {
windows = JSON.parse(this.text)
} catch (error) {
console.error(
- "Failed to parse niri windows:",
+ "Failed to parse Niri windows:",
error
)
@@ -31,74 +138,74 @@ Item {
return
}
- var app = root.pendingApp.toLowerCase()
+ var notificationApp = root.pendingApp
root.pendingApp = ""
- if (Config.notificationVesktopNames.indexOf(app) !== -1) {
- for (var i = 0; i < windows.length; i++) {
- var niriWindow = windows[i]
- var appId = (niriWindow.app_id || "").toLowerCase()
-
- if (appId === Config.notificationVesktopAppId) {
- console.log(
- "FOCUSING VESKTOP WINDOW:",
- niriWindow.id,
- niriWindow.title
- )
-
- focusProcess.exec([
- "niri",
- "msg",
- "action",
- "focus-window",
- "--id",
- String(niriWindow.id)
- ])
-
- return
- }
- }
+ if (!notificationApp) {
+ console.warn("Notification focus: empty app name")
+ return
+ }
- console.log(
- "No matching Niri window found for:",
- app
+ if (!Array.isArray(windows)) {
+ console.error(
+ "Niri windows response is not an array"
)
-
return
}
- for (var j = 0; j < windows.length; j++) {
- var window = windows[j]
- var windowAppId = (window.app_id || "").toLowerCase()
+ var bestWindow = null
+ var bestScore = 0
+
+ for (var i = 0; i < windows.length; i++) {
+ var window = windows[i]
- if (
- windowAppId === app ||
- windowAppId === app + ".desktop"
- ) {
- console.log(
- "FOCUSING WINDOW:",
- window.id,
- window.app_id,
- window.title
- )
+ if (!window || window.id === undefined)
+ continue
- focusProcess.exec([
- "niri",
- "msg",
- "action",
- "focus-window",
- "--id",
- String(window.id)
- ])
+ var appId = window.app_id || ""
+ var title = window.title || ""
- return
+ var score = matchScore(
+ notificationApp,
+ appId,
+ title
+ )
+
+ if (score > bestScore) {
+ bestScore = score
+ bestWindow = window
}
}
+ if (!bestWindow) {
+ console.log(
+ "No matching Niri window found:",
+ notificationApp
+ )
+ return
+ }
+
console.log(
- "No matching Niri window found for:",
- app
+ "FOCUSING WINDOW:",
+ bestWindow.id,
+ "notification app:",
+ notificationApp,
+ "app_id:",
+ bestWindow.app_id,
+ "title:",
+ bestWindow.title,
+ "score:",
+ bestScore
)
+
+ focusProcess.exec([
+ "niri",
+ "msg",
+ "action",
+ "focus-window",
+ "--id",
+ String(bestWindow.id)
+ ])
}
}
}
@@ -111,7 +218,16 @@ Item {
if (!notification)
return
- root.pendingApp = notification.appName
+ var app = notification.appName || ""
+
+ if (!app) {
+ console.warn(
+ "Notification has no application name"
+ )
+ return
+ }
+
+ root.pendingApp = app
windowsProcess.exec([
"niri",