777genius/claude-notifications-go

macOS: click-to-focus fails silently when target terminal window is minimized (AXRaise is a no-op)

開放

#67 建立於 2026年4月10日

 (1 則留言) (0 個反應) (0 位負責人)Go (100 個分叉)auto 404
bughelp wanted

倉庫指標

星標
 (759 顆星)
PR 合併指標
 (PR 指標待抓取)

描述

Summary

On macOS, clicking a notification to focus a terminal window silently fails when the target window is minimized to the Dock. The focused app activates but the target window stays minimized, so nothing visible happens.

Affects both code paths in internal/notifier/ax_focus_darwin.go:

  • raiseWindowByAXDocument (Ghostty via AXDocument / OSC 7 file URL)
  • raiseWindowByAXTitle (other terminals via AXTitle folder matching)

Environment

  • macOS 14.5 (Sonoma, Darwin 23.5.0)
  • Plugin v1.36.6 (installed via marketplace)
  • Terminal: Ghostty (com.mitchellh.ghostty), but same bug applies to every terminal path that ends in AXRaise
  • Accessibility and Screen Recording permissions granted

Steps to reproduce

  1. Open Claude Code in Ghostty at e.g. ~/work.
  2. Minimize the Ghostty window (yellow traffic light).
  3. Trigger a notification (e.g., Stop event on task completion).
  4. Click the notification banner.

Expected: Ghostty activates AND the minimized window is restored (un-minimized) and raised.

Actual: Ghostty activates (app icon bounces / menu bar switches) but the window stays minimized in the Dock. Notification click has no visible effect.

Root cause

Both raiseWindowByAXDocument and raiseWindowByAXTitle iterate AXWindows, match the target window, then call:

```c AXUIElementPerformAction(w, CFSTR("AXRaise")); AXUIElementSetAttributeValue(appEl, CFSTR("AXFrontmost"), kCFBooleanTrue); ```

On macOS, AXRaise is a no-op on a window whose AXMinimized attribute is true. A minimized window must be un-minimized first via:

```c AXUIElementSetAttributeValue(w, CFSTR("AXMinimized"), kCFBooleanFalse); ```

NSRunningApplication activateWithOptions: (called in `activateByPID`) also does not un-minimize windows; it only brings the app's non-minimized windows forward.

Proposed fix

Before calling `AXRaise`, check and clear `AXMinimized` in both helpers. Minimal diff:

```diff --- a/internal/notifier/ax_focus_darwin.go +++ b/internal/notifier/ax_focus_darwin.go @@ raiseWindowByAXDocument @@ if (ok && strcmp(buf, fileURL) == 0) {

  •   	CFTypeRef minRef = NULL;
    
  •   	if (AXUIElementCopyAttributeValue(w, CFSTR(\"AXMinimized\"), &minRef) == kAXErrorSuccess && minRef) {
    
  •   		if (CFBooleanGetValue((CFBooleanRef)minRef)) {
    
  •   			AXUIElementSetAttributeValue(w, CFSTR(\"AXMinimized\"), kCFBooleanFalse);
    
  •   		}
    
  •   		CFRelease(minRef);
    
  •   	}
      	AXUIElementPerformAction(w, CFSTR(\"AXRaise\"));
      	AXUIElementSetAttributeValue(appEl, CFSTR(\"AXFrontmost\"), kCFBooleanTrue);
      	found = 1;
      }
    

@@ raiseWindowByAXTitle @@ if (matched) {

  •   	CFTypeRef minRef = NULL;
    
  •   	if (AXUIElementCopyAttributeValue(w, CFSTR(\"AXMinimized\"), &minRef) == kAXErrorSuccess && minRef) {
    
  •   		if (CFBooleanGetValue((CFBooleanRef)minRef)) {
    
  •   			AXUIElementSetAttributeValue(w, CFSTR(\"AXMinimized\"), kCFBooleanFalse);
    
  •   		}
    
  •   		CFRelease(minRef);
    
  •   	}
      	AXUIElementPerformAction(w, CFSTR(\"AXRaise\"));
      	AXUIElementSetAttributeValue(appEl, CFSTR(\"AXFrontmost\"), kCFBooleanTrue);
      	found = 1;
      	break;
      }
    

```

Setting `AXMinimized = false` triggers the Dock un-minimize animation identical to a manual Dock icon click. After that completes, `AXRaise` + `AXFrontmost` work as usual. No extra permissions needed (Accessibility is already a prerequisite for the existing calls).

A small delay (e.g. `usleep(150000)`) between the un-minimize and `AXRaise` may be needed on slower machines while the un-minimize animation plays; the existing `retryWindowFocus` backoff in Go (150/250/400 ms) should cover this.

Note on the other fallback path

`findSwitchAndActivate` + `switchToWindowSpace` uses `CGSCopySpacesForWindows` / `CGSManagedDisplaySetCurrentSpace` to cross Spaces, but `CGWindowListCopyWindowInfo` by default returns the minimized window's off-screen bounds, and the same `AXRaise` no-op applies afterwards. The same un-minimize step would fix that path as well.

Happy to open a PR with the full patch and tests if that's welcome.

貢獻者指南