diff --git a/desktopenvs/hyprdrive/beacon/main.py b/desktopenvs/hyprdrive/beacon/main.py index 343c66c..fb237b5 100644 --- a/desktopenvs/hyprdrive/beacon/main.py +++ b/desktopenvs/hyprdrive/beacon/main.py @@ -14,6 +14,7 @@ look instead of a plain popup. from __future__ import annotations import os +import signal import sys from pathlib import Path @@ -52,8 +53,17 @@ class BeaconApp(Gtk.Application): self._name_id = Gio.bus_own_name( Gio.BusType.SESSION, FDN_NAME, Gio.BusNameOwnerFlags.NONE, 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 + 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: assert self.window is not None self._server = NotificationServer(connection, self.window) diff --git a/desktopenvs/hyprdrive/beacon/window.py b/desktopenvs/hyprdrive/beacon/window.py index 1ccb710..3b473c1 100644 --- a/desktopenvs/hyprdrive/beacon/window.py +++ b/desktopenvs/hyprdrive/beacon/window.py @@ -85,6 +85,13 @@ class BeaconWindow(Gtk.ApplicationWindow): self._pending_reason[nid] = reason 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 ------------------------------------------------------- _pending_reason: dict[int, int] = {} diff --git a/desktopenvs/hyprdrive/config-updater/updater.conf b/desktopenvs/hyprdrive/config-updater/updater.conf index abf7a1d..6fa7914 100644 --- a/desktopenvs/hyprdrive/config-updater/updater.conf +++ b/desktopenvs/hyprdrive/config-updater/updater.conf @@ -12,8 +12,9 @@ SOURCE_BASE = ~/Dotfiles/desktopenvs/hyprdrive # ── deployed as ~/.config/ ───────────────────────────────────────────── config alacritty config astro-menu +config beacon config btop -config dunst +config ghostty config gtk-3.0 config hypr except usr config horizon-dock @@ -27,6 +28,7 @@ config xfce4 # ── intentionally not managed here ─────────────────────────────────────────── 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 greetd-tuigreet # deployed to /etc/greetd/ at install time ignore spicetify # managed separately (spicetify handles its own config) diff --git a/desktopenvs/hyprdrive/hypr/usr/binds.lua b/desktopenvs/hyprdrive/hypr/usr/binds.lua index 16891d9..e703d55 100644 --- a/desktopenvs/hyprdrive/hypr/usr/binds.lua +++ b/desktopenvs/hyprdrive/hypr/usr/binds.lua @@ -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 + U", hl.dsp.exec_cmd("chamel clear")) 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 .. " + 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")) diff --git a/desktopenvs/hyprdrive/scripts/screenrec.sh b/desktopenvs/hyprdrive/scripts/screenrec.sh index 9f63495..34f3fb5 100755 --- a/desktopenvs/hyprdrive/scripts/screenrec.sh +++ b/desktopenvs/hyprdrive/scripts/screenrec.sh @@ -3,7 +3,11 @@ endrec () { 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" } diff --git a/desktopenvs/hyprdrive/scripts/timer-run b/desktopenvs/hyprdrive/scripts/timer-run index f09ce97..e97472a 100755 --- a/desktopenvs/hyprdrive/scripts/timer-run +++ b/desktopenvs/hyprdrive/scripts/timer-run @@ -42,13 +42,13 @@ DURATION_STR=$(fmt_dur "$TOTAL") NOTIF_SUMMARY="⏰ Timer done${LABEL:+ — $LABEL}" 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 -# 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 local_uid=$(id -u) # 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 \ | tr '\0' '\n' \ | grep '^DBUS_SESSION_BUS_ADDRESS=' \