Skip to content

Add urgent-view feature (Win+U)#10

Merged
somanysteves merged 5 commits intomasterfrom
feat/urgent-view
Apr 30, 2026
Merged

Add urgent-view feature (Win+U)#10
somanysteves merged 5 commits intomasterfrom
feat/urgent-view

Conversation

@somanysteves
Copy link
Copy Markdown
Owner

Summary

  • AwesomeWM-style urgent windows: when a managed window flashes its taskbar entry (HSHELL_FLASH), its non-active views light up red on the bar; Win+U cycles through urgent views, clearing each on activation.
  • Two test surfaces: Yunit (mocked-state dispatch + ordering regression guards) and a new bugn-bench --scenario urgent real-OS round-trip that spawns a cmd, lets the real shell hook manage it, calls real FlashWindowEx, and asserts the urgency state and Win+U jump.
  • Side fixes pulled in along the way: Window_isHung(0) guard, Window_set(0, …) guard in Monitor_activateView, headless guards in Bar_updateView / Bar_updateTitle, and Window_getHidden extracted into its own file (matches View_arrange stub pattern).

Bugs the bench-style test caught that Yunit didn't

  1. Manager_managedWndIds is hex-formatted in production (0x...) but Yunit synthesized decimal — so the original lParam-to-decimal "fix" passed Yunit and broke production. Replaced with Manager_isManaged doing numeric comparison and returning the stored-key form.
  2. Window_#%wndId%_isUrgent was never initialized as a global by Manager__setWinProperties, so the dynamic write in Manager_markUrgent created a function-local that vanished on return. Yunit masked it because Begin() pre-initialized that global. Fix: initialize it at manage time, clear at unmanage time.

Test plan

  • .\test.bat → 49/49 green (Yunit + dispatch integration).
  • .\dist\bugn-bench.exe --scenario urgent exits 0 and the log shows "PASS — real-OS HSHELL_FLASH → Manager_markUrgent → Manager_activateUrgentView round-trip verified".
  • Manual smoke: open Notepad, send to a non-active view, switch away, run .\tools\flash-window.ps1 -TitlePattern "Notepad"; verify the view's bar button turns red and Win+U jumps to it.
  • Multiple urgent views simultaneously: two windows on different non-active views, flash each, both red, Win+U cycles through.

🤖 Generated with Claude Code

Mirrors AwesomeWM's urgent-window behavior: when a managed window flashes
its taskbar entry (HSHELL_FLASH), its non-active views light up red on
the bar; Win+U cycles through urgent views, clearing each on activation.

Two test surfaces:
- tests/test_Manager_urgentView.ahk: Yunit unit + dispatch integration
  against synthesized state, including regression guards for the
  HSHELL_FLASH-above-early-return ordering invariant.
- src/Bench_urgent.ahk: bugn-bench --scenario urgent runs the round-trip
  end-to-end against real bug.n state — spawns a cmd, lets the real
  shell hook manage it, calls real FlashWindowEx, asserts urgency flags
  flip and Win+U jumps to the urgent view.

The bench-style test caught two production-only bugs the Yunit harness
masked: Manager_managedWndIds is hex-formatted in production (decimal in
synthesized tests), and Window_#%wndId%_isUrgent was never initialized
as a global so dynamic writes from Manager_markUrgent created locals
that vanished on return. Manager_isManaged now does numeric comparison
and returns the stored-key form so dynamic-var lookups in
Manager_markUrgent match Manager__setWinProperties' format.

Side fixes pulled in along the way:
- Window_isHung guards against wndId=0 (SendMessage ahk_id 0 throws).
- Monitor_activateView guards Window_set(0, "AlwaysOnTop", "Off").
- Bar_updateView / Bar_updateTitle no-op when Bar_initialized is unset
  so the Yunit harness can run them headless.
- Window_getHidden extracted to its own file so the test runner can
  swap in a controllable stub (matches the View_arrange pattern).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 29, 2026 00:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an “urgent view” concept to bug.n: views containing a flashing managed window are highlighted (red), and Win+U cycles to the next urgent view while clearing urgency upon activation. This is integrated at the shell-hook layer (HSHELL_FLASH) and supported by both Yunit tests and a new real-OS bench scenario.

Changes:

  • Handle HSHELL_FLASH by marking non-active views urgent and add Win+U (#u) to jump/cycle through urgent views.
  • Clear urgency on view activation and render urgent views with a distinct bar color theme.
  • Add coverage: new Yunit suite + a new bugn-bench --scenario urgent end-to-end scenario; extract Window_getHidden to enable test stubbing.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tools/flash-window.ps1 Helper script to trigger HSHELL_FLASH via FlashWindowEx for manual smoke testing.
tests/test_Manager_urgentView.ahk New Yunit suite covering urgent marking, clearing on activation, dispatch ordering, and Win+U cycling.
tests/stubs_io.ahk Adds a controllable stub for Window_getHidden to validate dispatch ordering.
tests/run.ahk Registers the new urgent-view test suite in the runner.
src/Window_getHidden.ahk Extracts Window_getHidden into its own file to support stubbing in tests.
src/Window.ahk Removes inlined Window_getHidden impl; adds Window_isHung(0) guard.
src/View.ahk Initializes per-view ..._isUrgent state.
src/Monitor.ahk Clears urgency when activating a destination view; guards Window_set(0, ...).
src/Manager.ahk Adds Manager_isManaged, urgent dispatch for HSHELL_FLASH, and Win+U cycling logic.
src/Main.ahk Includes the new Window_getHidden.ahk implementation.
src/Config.ahk Adds urgent-view hotkey and updates default palette for urgent highlighting.
src/Bench_urgent.ahk New real-OS end-to-end urgent scenario exercising shell hook + FlashWindowEx.
src/Bench_main.ahk Adds --scenario urgent plumbing and includes Bench_urgent.ahk.
src/Bar.ahk Adds headless guards for update functions and renders urgent views using palette #3.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Config.ahk
Comment thread src/Config.ahk
Comment thread src/Config.ahk
Comment thread src/Monitor.ahk Outdated
Comment thread src/Manager.ahk Outdated
Comment thread src/Manager.ahk
somanysteves and others added 3 commits April 29, 2026 07:36
Closes the urgency loop introduced by the urgent-view feature: when
Claude Code is waiting on user input (permission prompt, idle await),
its Notification hook flashes the alacritty terminal hosting that
session, which bug.n picks up via HSHELL_FLASH and lights the holding
view red on the bar.

tools/flash-window.ps1 gains an -AncestorProcess mode that walks up
the parent process chain from the hook's PowerShell process (hook
shell → claude.exe → ... → alacritty.exe) and flashes a top-level
window owned by that ancestor's PID. The walk is needed because the
Notification hook payload doesn't include a terminal PID — only
session_id, cwd, etc. The existing -Process / -TitlePattern modes
are unchanged.

tools/claude-attention-hook.md documents the integration and the
~/.claude/settings.json snippet for setting it up on a new machine,
including how to override -AncestorProcess for non-alacritty
terminals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bar_updateStatus and Bar_updateView read indexed globals like
Config_backColor_#3_#1 (view slot) and Config_backColor_#3_#8
(batteryStatus slot), produced by Config_initColors's StringSplit on
';'. If a future edit to the palette strings drops or adds a ';',
slot 8 silently shifts and the wrong color reaches Bar_updateStatus.

tests/test_Config_urgentPalette.ahk locks the slot mapping for all
three palette colors (back/fore/font, palette #3) — slot count = 9,
slot 1 = urgent fill, slot 8 = batteryStatus, slots 2-7 empty.
Negative-tested by dropping one ';' from the production string: the
suite fails with slot count = 8 and 'ff8040' at slot 7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Monitor_activateView cleared urgency on the destination view only for
aMonitor, not for the other monitors that Config_syncMonitorViews=1
pulls onto the same view. The result: those synced monitors land on
view i as their *active* view but with View_#m_#i_isUrgent still True,
so the bar renders the active view with the urgent palette.

Move the urgency-clear into the Loop, % n body keyed by m so every
synced monitor is cleared. Single-monitor and syncMonitorViews=0
behavior is unchanged (n = 1, m = aMonitor — same effect as before).

Add a regression test (ActivateView_SyncMonitorViews_ClearsUrgencyOn
AllSyncedMonitors) that fails against master and passes against the
fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 29, 2026 12:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Bench_urgent.ahk
Comment thread src/Bar.ahk
Manager_onShellMessage called Manager_isManaged for every shell
message, but the result was only consumed by the HSHELL_FLASH
dispatch on the next line. Manager_isManaged scans Manager_managedWndIds
with StringTrimRight + Loop, PARSE — O(n) over managed windows. Shell
messages fire on every activate/create/destroy/redraw, so the scan
ran dozens of times per minute only to be discarded.

Move the call inside the (wParam = HSHELL_FLASH) And lParam branch.
Semantics unchanged: the existing ShellHook_HSHELL_FLASH_* tests
cover all three flash branches (managed dispatch, hidden window
dispatch, unmanaged ignore) and pass against the refactor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@somanysteves somanysteves merged commit d5415d3 into master Apr 30, 2026
4 checks passed
@somanysteves somanysteves deleted the feat/urgent-view branch April 30, 2026 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants