feat(hyprdrive): switch notifications from dunst to beacon
beacon (the Cosmonaut Shell notif daemon) already renders its holo fade-in-from-noise intro (materialise out of static), but dunst held the org.freedesktop.Notifications bus so beacon never started. Make beacon the deployed and active notification daemon: - updater.conf: manage `config beacon`; drop `config dunst` (now `ignore`d, superseded). Also carries the pre-existing `config ghostty` line that was already sitting uncommitted in this file. - beacon: add a SIGUSR1 close-all handler (window.close_all) so the old `dunstctl close-all` keybind has an equivalent. - binds.lua: Super+Ctrl+C now runs `pkill -USR1 -f '[b]eacon/main.py'` (bracket idiom avoids pkill self-matching its own wrapper). - screenrec.sh: `dunstctl close` -> freedesktop CloseNotification via gdbus. - timer-run: resolve the session bus via the beacon process, not dunst. hyprlua keeps its own independent updater.conf + dunst and is untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>main
parent
f94a825c82
commit
b7eba3f967
|
|
@ -14,6 +14,7 @@ look instead of a plain popup.
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
@ -52,8 +53,17 @@ class BeaconApp(Gtk.Application):
|
||||||
self._name_id = Gio.bus_own_name(
|
self._name_id = Gio.bus_own_name(
|
||||||
Gio.BusType.SESSION, FDN_NAME, Gio.BusNameOwnerFlags.NONE,
|
Gio.BusType.SESSION, FDN_NAME, Gio.BusNameOwnerFlags.NONE,
|
||||||
self._on_bus_acquired, None, self._on_name_lost)
|
self._on_bus_acquired, None, self._on_name_lost)
|
||||||
|
# SIGUSR1 = close every visible card (the `Super+Ctrl+C` keybind, which
|
||||||
|
# used to run `dunstctl close-all`).
|
||||||
|
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGUSR1,
|
||||||
|
self._on_sigusr1)
|
||||||
self.hold() # stay alive with no visible window
|
self.hold() # stay alive with no visible window
|
||||||
|
|
||||||
|
def _on_sigusr1(self) -> bool:
|
||||||
|
if self.window is not None:
|
||||||
|
self.window.close_all()
|
||||||
|
return GLib.SOURCE_CONTINUE
|
||||||
|
|
||||||
def _on_bus_acquired(self, connection: Gio.DBusConnection, _name: str) -> None:
|
def _on_bus_acquired(self, connection: Gio.DBusConnection, _name: str) -> None:
|
||||||
assert self.window is not None
|
assert self.window is not None
|
||||||
self._server = NotificationServer(connection, self.window)
|
self._server = NotificationServer(connection, self.window)
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,13 @@ class BeaconWindow(Gtk.ApplicationWindow):
|
||||||
self._pending_reason[nid] = reason
|
self._pending_reason[nid] = reason
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def close_all(self, reason: int = 2) -> None:
|
||||||
|
"""Dismiss every visible card (the old `dunstctl close-all` keybind).
|
||||||
|
reason 2 = dismissed by user. Each card plays its dissolve; removal and
|
||||||
|
the NotificationClosed signals follow as the outros finish."""
|
||||||
|
for nid in list(self._order):
|
||||||
|
self.close_notification(nid, reason=reason)
|
||||||
|
|
||||||
# -- card lifecycle -------------------------------------------------------
|
# -- card lifecycle -------------------------------------------------------
|
||||||
_pending_reason: dict[int, int] = {}
|
_pending_reason: dict[int, int] = {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ SOURCE_BASE = ~/Dotfiles/desktopenvs/hyprdrive
|
||||||
# ── deployed as ~/.config/<name> ─────────────────────────────────────────────
|
# ── deployed as ~/.config/<name> ─────────────────────────────────────────────
|
||||||
config alacritty
|
config alacritty
|
||||||
config astro-menu
|
config astro-menu
|
||||||
|
config beacon
|
||||||
config btop
|
config btop
|
||||||
config dunst
|
config ghostty
|
||||||
config gtk-3.0
|
config gtk-3.0
|
||||||
config hypr except usr
|
config hypr except usr
|
||||||
config horizon-dock
|
config horizon-dock
|
||||||
|
|
@ -27,6 +28,7 @@ config xfce4
|
||||||
|
|
||||||
# ── intentionally not managed here ───────────────────────────────────────────
|
# ── intentionally not managed here ───────────────────────────────────────────
|
||||||
ignore config-updater # the updater itself
|
ignore config-updater # the updater itself
|
||||||
|
ignore dunst # superseded by beacon (the Cosmonaut Shell notif daemon)
|
||||||
ignore CRT # referenced from dotfiles path directly in binds.conf
|
ignore CRT # referenced from dotfiles path directly in binds.conf
|
||||||
ignore greetd-tuigreet # deployed to /etc/greetd/ at install time
|
ignore greetd-tuigreet # deployed to /etc/greetd/ at install time
|
||||||
ignore spicetify # managed separately (spicetify handles its own config)
|
ignore spicetify # managed separately (spicetify handles its own config)
|
||||||
|
|
|
||||||
|
|
@ -325,7 +325,7 @@ hl.bind(mainMod .. " + CTRL + X", hl.dsp.exec_cmd("hyprctl hyprsunset identity")
|
||||||
hl.bind(mainMod .. " + CTRL + I", hl.dsp.exec_cmd("chamel toggle"))
|
hl.bind(mainMod .. " + CTRL + I", hl.dsp.exec_cmd("chamel toggle"))
|
||||||
hl.bind(mainMod .. " + CTRL + U", hl.dsp.exec_cmd("chamel clear"))
|
hl.bind(mainMod .. " + CTRL + U", hl.dsp.exec_cmd("chamel clear"))
|
||||||
hl.bind(mainMod .. " + CTRL + Z", hl.dsp.exec_cmd("chamel clear-and-deactivate"))
|
hl.bind(mainMod .. " + CTRL + Z", hl.dsp.exec_cmd("chamel clear-and-deactivate"))
|
||||||
hl.bind(mainMod .. " + CTRL + C", hl.dsp.exec_cmd("dunstctl close-all"))
|
hl.bind(mainMod .. " + CTRL + C", hl.dsp.exec_cmd("pkill -USR1 -f '[b]eacon/main.py'"))
|
||||||
hl.bind(mainMod .. " + CTRL + G", hl.dsp.exec_cmd("~/.config/scripts/onscreenkb.sh"))
|
hl.bind(mainMod .. " + CTRL + G", hl.dsp.exec_cmd("~/.config/scripts/onscreenkb.sh"))
|
||||||
hl.bind(mainMod .. " + SHIFT + C", hl.dsp.exec_cmd("~/.config/scripts/caffeine.sh"))
|
hl.bind(mainMod .. " + SHIFT + C", hl.dsp.exec_cmd("~/.config/scripts/caffeine.sh"))
|
||||||
hl.bind(mainMod .. " + SHIFT + B", hl.dsp.exec_cmd("[tag +centered-S] kitty bash ~/.config/scripts/enroll-biometrics.sh"))
|
hl.bind(mainMod .. " + SHIFT + B", hl.dsp.exec_cmd("[tag +centered-S] kitty bash ~/.config/scripts/enroll-biometrics.sh"))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@
|
||||||
|
|
||||||
endrec () {
|
endrec () {
|
||||||
killall -s SIGINT wf-recorder
|
killall -s SIGINT wf-recorder
|
||||||
dunstctl close $nid
|
# beacon (the notif daemon) has no dunstctl; close the "recording started"
|
||||||
|
# card via the freedesktop CloseNotification method instead.
|
||||||
|
[ -n "$nid" ] && gdbus call --session --dest org.freedesktop.Notifications \
|
||||||
|
--object-path /org/freedesktop/Notifications \
|
||||||
|
--method org.freedesktop.Notifications.CloseNotification "$nid" >/dev/null 2>&1
|
||||||
notify-send "recording ended - output to $outfile"
|
notify-send "recording ended - output to $outfile"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ DURATION_STR=$(fmt_dur "$TOTAL")
|
||||||
NOTIF_SUMMARY="⏰ Timer done${LABEL:+ — $LABEL}"
|
NOTIF_SUMMARY="⏰ Timer done${LABEL:+ — $LABEL}"
|
||||||
NOTIF_BODY="Set for ${DURATION_STR}. Finished at $(date '+%H:%M:%S')."
|
NOTIF_BODY="Set for ${DURATION_STR}. Finished at $(date '+%H:%M:%S')."
|
||||||
|
|
||||||
# ── dunst notification ────────────────────────────────────────────────────────
|
# ── desktop notification ──────────────────────────────────────────────────────
|
||||||
# notify-send needs DBUS_SESSION_BUS_ADDRESS. If not in env, find it via the
|
# notify-send needs DBUS_SESSION_BUS_ADDRESS. If not in env, find it via the
|
||||||
# running dunst process (reliable on single-user Wayland/Hyprland setups).
|
# running beacon notif daemon (reliable on single-user Wayland/Hyprland setups).
|
||||||
if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]]; then
|
if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]]; then
|
||||||
local_uid=$(id -u)
|
local_uid=$(id -u)
|
||||||
# try to grab it from the environment of any process owned by this user
|
# try to grab it from the environment of any process owned by this user
|
||||||
for pid in $(pgrep -u "$local_uid" dunst 2>/dev/null); do
|
for pid in $(pgrep -u "$local_uid" -f '[b]eacon/main.py' 2>/dev/null); do
|
||||||
addr=$(cat /proc/$pid/environ 2>/dev/null \
|
addr=$(cat /proc/$pid/environ 2>/dev/null \
|
||||||
| tr '\0' '\n' \
|
| tr '\0' '\n' \
|
||||||
| grep '^DBUS_SESSION_BUS_ADDRESS=' \
|
| grep '^DBUS_SESSION_BUS_ADDRESS=' \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue