53 lines
1.9 KiB
Bash
Executable file
53 lines
1.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Monitors D-Bus for org.freedesktop.Notifications.Notify method calls.
|
|
# For each notification, captures the sender process PID and outputs:
|
|
# <notification-id>:<sender-pid>
|
|
# Quickshell reads this to know which process originated each notification,
|
|
# allowing it to walk the /proc tree and focus the exact window that sent it.
|
|
|
|
get_pid() {
|
|
busctl call org.freedesktop.DBus /org/freedesktop/DBus \
|
|
org.freedesktop.DBus GetConnectionUnixProcessID s "$1" 2>/dev/null \
|
|
| awk '{print $2}'
|
|
}
|
|
|
|
# Maps serial → pid so concurrent notifications don't clobber each other.
|
|
declare -A pending_pids
|
|
|
|
awaiting_nid=false
|
|
pending_pid=""
|
|
|
|
dbus-monitor --session "dest='org.freedesktop.Notifications'" 2>/dev/null | \
|
|
while IFS= read -r line; do
|
|
line="${line#"${line%%[![:space:]]*}"}" # trim leading whitespace
|
|
|
|
if [[ "$line" == *"method call"* && "$line" == *"member=Notify"* ]]; then
|
|
if [[ "$line" =~ sender=([^[:space:],;]+) ]]; then sender="${BASH_REMATCH[1]}"; fi
|
|
if [[ "$line" =~ serial=([0-9]+) ]]; then serial="${BASH_REMATCH[1]}"; fi
|
|
if [[ "$sender" == :* && -n "$serial" ]]; then
|
|
pid=$(get_pid "$sender")
|
|
if [[ -n "$pid" && "$pid" != "0" ]]; then
|
|
pending_pids["$serial"]="$pid"
|
|
fi
|
|
fi
|
|
|
|
elif [[ "$line" == *"method return"* ]]; then
|
|
if [[ "$line" =~ reply_serial=([0-9]+) ]]; then
|
|
reply="${BASH_REMATCH[1]}"
|
|
if [[ -n "${pending_pids[$reply]}" ]]; then
|
|
awaiting_nid=true
|
|
pending_pid="${pending_pids[$reply]}"
|
|
unset "pending_pids[$reply]"
|
|
fi
|
|
fi
|
|
|
|
elif [[ "$awaiting_nid" == true ]]; then
|
|
if [[ "$line" =~ ^uint32[[:space:]]+([0-9]+) ]]; then
|
|
echo "${BASH_REMATCH[1]}:${pending_pid}"
|
|
awaiting_nid=false
|
|
pending_pid=""
|
|
elif [[ -n "$line" ]]; then
|
|
awaiting_nid=false
|
|
fi
|
|
fi
|
|
done
|