777genius/claude-notifications-go

Loading cursor persists after clicking notification on GNOME/Wayland

Offen

#61 geöffnet am 31.03.2026

 (12 Kommentare) (1 Reaktion) (0 zugewiesene Personen)Go (100 Forks)auto 404
bughelp wantedlinux

Repository-Metriken

Stars
 (759 Sterne)
PR-Merge-Metriken
 (PR-Metriken ausstehend)

Beschreibung

Problem

On Ubuntu 24.04 (GNOME/Wayland), clicking a notification from claude-notifications causes the mouse cursor to change to a loading spinner for ~15 seconds, even though click-to-focus works correctly and the terminal window is focused immediately.

Root Cause

D-Bus monitoring (dbus-monitor --session "interface='org.freedesktop.Notifications'") reveals the issue:

signal member=ActivationToken
   uint32 162
   string "gnome-shell/Visual Studio Code/4019-22-gram_TIME139555122"

signal member=ActionInvoked
   uint32 162
   string "default"

signal member=NotificationClosed
   uint32 162
   uint32 2

When the user clicks a notification, GNOME Shell emits three signals in order:

  1. ActivationToken — GNOME Shell creates a Wayland xdg-activation-v1 token for the app specified in the desktop-entry hint (e.g., "Visual Studio Code"). This is where the loading cursor starts.
  2. ActionInvoked — Our daemon receives this signal and successfully focuses the correct window.
  3. NotificationClosed — The notification is dismissed.

The problem: GNOME Shell creates an activation token expecting the target app (e.g., VS Code) to consume it via the xdg-activation-v1 Wayland protocol. However, the target app never receives or consumes this token — our daemon handles the focus instead. The unconsumed token causes GNOME Shell to show the loading cursor until its startup notification timeout (~15 seconds).

The desktop-entry hint was added in PR #42 to fix a bug where clicking a notification opened Nautilus instead of the terminal. The hint correctly tells GNOME Shell which app the notification belongs to, but it also triggers the activation token behavior.

Proposed Solution

Create a claude-notifications.desktop file with StartupNotify=false and use it as the desktop-entry hint instead of the terminal's desktop entry.

Desktop file (~/.local/share/applications/claude-notifications.desktop):

[Desktop Entry]
Name=Claude Notifications
Type=Application
Icon=utilities-terminal
Exec=true
NoDisplay=true
StartupNotify=false
Terminal=false

Code change in internal/daemon/server.go:

Hints: map[string]dbus.Variant{
    "desktop-entry":  dbus.MakeVariant("claude-notifications"),
    "suppress-sound": dbus.MakeVariant(true),
},

Why this works:

  • desktop-entry is still present → GNOME Shell knows which app the notification belongs to → no Nautilus fallback (PR #42 fix preserved)
  • StartupNotify=false → GNOME Shell does NOT create an activation token → no loading cursor
  • Our daemon still receives ActionInvoked signal and handles window focus correctly
  • NoDisplay=true → the desktop entry doesn't appear in app launchers

Trade-off: Notifications will show as "Claude Notifications" in GNOME's notification panel instead of being grouped under the terminal app. This is acceptable since the daemon handles focus correctly via ActionInvoked.

Environment

  • Ubuntu 24.04
  • GNOME Shell on Wayland
  • claude-notifications-go with click-to-focus enabled

Contributor Guide