Repository navigation
fix: manual window moves stick; popout opens on the clicked screen and from SUPER+CTRL+<n> - #109
Conversation
sameAddress() compared ownToplevel.lastIpcObject.address (0x-prefixed) against the raw movewindowv2 IPC event's address (bare hex) with no normalization, so it never matched. Every real user move fell through to strayReturn 400ms later, which misread it as a stray idle/DPMS remap and silently moved the window back to its old saved home. This made manually moving the window to a new workspace never actually stick, on any workspace. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The panel exists only on the leader widget (first screen), and a click on another screen's bar was forwarded as a bare `toggle`, so the popout always anchored to the leader's bar. Followers now send `toggleon <screen>`, and the leader re-anchors the panel to that screen's widget button (found via bar.moduleWidgets) before opening; the popout derives its screen from its anchor. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… first Omarchy routes a panel hotkey to the bar widget on the FOCUSED screen, but only the leader (first screen) owns a panel. On any other screen open() was a silent no-op that still reported success, so the shell logged no "summon:" warning and the hotkey simply did nothing. open() now goes through openOn(screen): the leader re-anchors to the asked-for screen (anchorPanel, shared with toggleOn) and opens; a follower forwards to the leader over IPC the way a click on its icon already does. The new IPC verb is openon, not toggleon: a hotkey that means "open" must not close a panel that is already up. close() on a follower forwards too. Touches no CLAUDE.md invariant; extends the nixfred#38 hotkey path (open/close/ opened on the widget) to multi-monitor bars. ui.test.ts pins the forwarding and asserts openOn never toggles. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d to 27 WHAT: the merge-day entry for #109 (joshhattan) in both contributor-facing logs, plus the W38 header corrected from 25 to 27 merged PRs (it was already one short before #109 landed; counted the distinct PR numbers in the section). WHY: standing rule, Fred 2026-09-18 — every merged PR gets a line THE DAY IT MERGES, with the contributor's name and X handle, never reconstructed on Sunday. The notes record what was actually verified here and what was not, including the part his DP-1/DP-2 testing carries, and the open follow-up on his handle: still nothing published, already asked on the PR. LR-T: blip, changelog, contributors, weekly-notes LR-D: blip LR-R: #109 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
WHAT: cuts 2.6.0. manifest.json, the README badge and the CHANGELOG heading move together (ui.test.ts pins all three to each other); the Unreleased section becomes the release section, as 2.5.0 did. Headline changes since 2.5.0, from eight contributors across 27 merged PRs this week alone: security codes offer to fill themselves beside the field (and now work in Zen and Firefox, where Gecko lies about writing), an unknown sender can be saved as a real contact on the Mac, right-click quotes a message as a reply, reading a group in Blip clears it on the phone, Send Later shows as Scheduled instead of sent, GIFs arrive as GIFs, a message carries several files, stamps cross the bridge as UTC, and a never-opened unread stopped slowing every poll. Also added here: the two CHANGELOG entries #109 shipped without. That PR carried three fixes and documented only the third, so the window-move fix and the clicked-screen popout had no user-facing line. VERIFIED before the bump: bun test 622 pass, 0 fail. Deployed to ~/.config/omarchy/plugins/nixfred.blip and the shell restarted; qs log clean for nixfred.blip; every popout verb driven live (open, close, toggle, toggleon, openon) and the panel screenshotted rendering under its bar icon. REAL multi-monitor check, which the merge commit said was NOT possible: a second output appeared mid-session (BEAM-IPAD, the iPad stream, at 5120,0). It is Quickshell.screens[0], so it holds the panel and DVI-I-1's widget is the follower. `openon DVI-I-1` re-anchored the panel onto DVI-I-1 (layer 0 0 5120 1440) while a bare `open` left it on BEAM-IPAD (5120 0 960 540). #109's re-anchoring is therefore confirmed on real hardware, not just through IPC. KNOWN, PRE-EXISTING, NOT FIXED HERE: the follower-to-leader forward hardcodes `qs -p /usr/share/omarchy/shell`. gus runs its shell from the dev link at ~/Projects/video.on.desktop.omarchy/omarchy/shell, so every forward exits 255 with "No running instances" and the summon silently reports ok. Four such calls predate #109 and it added two more. Raised with Fred separately. LR-T: blip, release, 2.6.0, versioning, multi-monitor LR-D: blip LR-K: version-lives-in-three-pinned-files, beam-ipad-is-a-real-second-output LR-R: #109, #110 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Merged, and shipped in 2.6.0. Thank you, this is a good catch. The address fix is the one I want to call out. How it was integrated: your branch was based on Verified here on the live shell, not just read: deployed, restarted, And the multi-monitor half got verified after all. I said in the merge commit that I could not check it, because this machine had one output attached. A second one then appeared mid-session (an iPad stream at Your separate open-only verb was the right call, and it meshes with Omarchy's own routing better than I expected: One thing you could not have known about, and it is not yours to fix. The follower-to-leader forward hardcodes Still open from #110: no X handle found for you anywhere public. If you want credit in the weekly post under a handle, say the word and I will use it; otherwise you are credited as |
…nning WHAT: BarWidget's six follower-to-leader forwards stop hardcoding `qs -p /usr/share/omarchy/shell` and use `Quickshell.shellDir`, the directory the running shell was loaded from. New `root.shellRoot` holds it; ui.test.ts gains a guard that fails on any re-hardcoded path. WHY: `qs -p` matches a running instance BY ITS CONFIG PATH. The literal is correct on a stock install and wrong the moment the shell runs from a checkout, which is what `omarchy dev link` does and what gus has been running all along. Every forward then exits 255 with "No running instances" — and the shell's own summon still returns ok, because Bar.summonBarWidget only checks that the widget exposes open(), not that anything happened. So on a second monitor the bar icon and SUPER+CTRL+<n> did nothing, silently, with no warning anywhere. Found while verifying #109, which is the sharp part: #109 is CORRECT, its new test passes, and its feature was still completely inert on this machine. Four of the six calls predate it; joshhattan's two copied the surrounding style and were right to. The bug was in the style. VERIFIED on real hardware, which earlier commits could not do. A second output appeared mid-session (BEAM-IPAD, the iPad stream, 5120x1080 at 5120,0) and it is Quickshell.screens[0], so IT owns the panel and the 5120x1440 desktop monitor is the follower. With DVI-I-1 focused: before qs -p /usr/share/omarchy/shell ... -> exit 255, no panel, summon "ok" after shell summon nixfred.blip -> panel on DVI-I-1 (0 0 5120 1440) and a bare `open` still anchors to the leader (5120 0 960 540), so the re-anchoring from #109 is confirmed in both directions on two real bars. * bun test 623 pass, 0 fail. * The guard was run against the PRE-FIX BarWidget.qml and FAILS there, then passes on the fix. A guard that cannot fail is not a guard. * Deployed and the shell restarted; bridge back to online=true, 298 threads, healthy=true; qs log clean for nixfred.blip. NOT verified: moving Hyprland focus ONTO BEAM-IPAD did not work from the CLI, so the leader-focused summon was exercised through the IPC verbs rather than by really focusing that output. SCOPE: Fred chose this over filing an issue (AskUserQuestion, 2026-09-20), as a patch release rather than amending 2.6.0, so nothing already pushed is rewritten. LR-T: blip, quickshell, ipc, multi-monitor, omarchy-dev-link, release LR-D: blip, desktop LR-K: qs-p-matches-by-config-path, summon-ok-does-not-mean-it-happened LR-R: #109, 2.6.1 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lay-off
WHAT: the leader rule leaves the BarWidget.qml binding for screen-leader.ts
(built to ScreenLeader.mjs like SendState.mjs and BinDir.mjs), from Brad
Larson. A widget leads only on the FIRST REAL screen; an unresolved widget
(QsWindow.window still null) leads only when exactly one real screen exists;
with no real screen nobody leads, so nothing maps the app window.
WHY: when the last output disappears (monitor powered off, or a DisplayPort
monitor dropping off in its sleep, a Samsung C49HG9x does this) Qt substitutes
QPlatformPlaceholderScreen: name "", geometry 0x0. Omarchy's bar is a Variants
over Quickshell.screens, so it builds a bar on the placeholder; Blip's widget
there satisfied `Quickshell.screens.length <= 1`, crowned itself, and restored
the app window from window.json (visible:true). Hyprland 0.56.2 segfaulted in
CDefaultFloatingAlgorithm::newTarget <- CWindow::mapWindow mapping a floating
window with no output. Four separate nights on Brad's machine. gus logged the
same "There are no outputs - creating placeholder screen" twice on 2026-09-20.
VERIFIED in Test Drive (Omarchy 4.0.2, Hyprland 0.56.2, Quickshell 0.3.1, the
crash stack exactly), not by reading the diff:
* bun test 629 pass, 0 fail; ScreenLeader.mjs is byte-identical to a fresh
`bun build` of screen-leader.ts; quickshell-core.qmltypes exposes name,
width and height on ShellScreen.
* The output was removed with `hyprctl eval 'hl.monitor({ output =
"Virtual-1", disabled = true })'` (`hyprctl keyword` is refused by the
Lua parser). Pre-fix build with the window open and floating: the
placeholder bar's Blip registered a second IpcHandler for nixfred.blip
(the "another handler is registered" warning) and a Blip window was
mapped, i.e. it crowned itself exactly as described.
* An instrumented copy of the PR build logged Quickshell's screen list at
every change. The placeholder presents as ["",0,0]. In the crash state,
screens=[["",0,0]] only, the new rule gave leader=false and the window
Loader off for both an unresolved widget and one resolved to the
placeholder. When Virtual-1 returned, leader=true on it and the window
came back on monitor 0.
* NOT reproduced: the segfault itself. Hyprland stands up a FALLBACK
1920x1080 output in the same event as the removal, and the window landed
there. FALLBACK is a real screen (name and size), so Blip leads on it;
that is correct, it is an output. The DRM-sleep race that leaves Hyprland
with no output while a client maps is what Brad hit and this VM cannot
stage.
* Observation, not a defect: in the transitional [FALLBACK, placeholder]
and [placeholder, Virtual-1] states an UNRESOLVED widget briefly leads
under the unchanged one-real-screen rule, then drops it once its own
screen resolves to the placeholder. A real output exists in both states.
LR-T: blip, leader-election, placeholder-screen, hyprland-crash, display-off, quickshell, test-drive
LR-D: blip
LR-K: qt-placeholder-screen-is-name-empty-0x0, hyprland-fallback-output-is-a-real-screen, hyprctl-keyword-refused-use-eval-hl-monitor
LR-R: #113, #109
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETCwBtUznDoR5qMkAEfzbd
What
Three fixes for multi-workspace / multi-monitor use, one commit each:
sameAddress()inBlipWindow.qmlcomparedownToplevel.lastIpcObject.address(0x5b5a…) with the rawmovewindowv2event address (5b5a…, no prefix) as plain strings, so it never matched. Thereason: "move"path from fix: keep the app on its workspace after idle #87 was therefore never taken, and ~400ms laterstrayReturnread the move as a stray remap and sent the window back to its old home. Both sides are now stripped of0xbefore comparing.toggle, so the popout always anchored to the leader's bar. Followers now sendtoggleon <screen>; the leader finds that screen's widget withbar.moduleWidgets(), re-anchors the panel to its button and bar, then opens it (the popout takes its screen from its anchor).SUPER+CTRL+<n>opens the popout on any screen, not just the first. Omarchy routes a panel hotkey to the widget on the focused screen, but only the leader owns a panel, so on any other screenopen()was a silent no-op that still reported success (nosummon:warning, the hotkey just did nothing).open()now goes throughopenOn(screen): the leader re-anchors to the asked-for screen and opens; a follower forwards to the leader over IPC like a click does. The new verb isopenon, nottoggleon, because a hotkey that means "open" must not close a panel that is already up.close()on a follower forwards too.Why
movewindowv2 …,6,6followed ~400ms later bymovewindowv2 …,1,1. The window's saved home was never updated, so it could not be moved off its first workspace.SUPER+CTRL+1did nothing at all. Omarchy's panel hotkeys reach Blip: expose opened on the bar widget #38 made the hotkey reach the widget (open/close/opened); this makes it work when that widget is a follower. Fix 3 reuses the anchoring from fix 2, which is why it belongs in this PR.The DEVLOG entry for #87 verified that a stray move is returned but not that a deliberate move is saved; QML has no unit tests and
ui.test.tsonly asserts that the stringsameAddressexists, so neither path was covered. Fix 3 adds aui.test.tsassertion that the follower forwards, thatopenOnnever toggles, and thatclose()forwards too (it fails against the previousBarWidget.qml).How it was verified
bun testis green (561 pass)hyprctl layersinstead, below)CLAUDE.md→ named below; doc not changedLive checks on Hyprland with two monitors (DP-1, DP-2):
window.jsonsaved"workspace":"6".ipc call nixfred.blip toggleon DP-2putsomarchy-keyboard-panelon DP-2;toggleon DP-1puts it on DP-1. I did not physically click the DP-2 bar icon; that path calls the sametoggleonIPC withownScreen.name.togglePanelAt right 1(whatSUPER+CTRL+1runs) previously produced noomarchy-keyboard-panellayer; after the fix it does, and the popout is visible on DP-2. Physically pressingSUPER+CTRL+1on DP-2 opens it. Theqs ipcverbopenon <screen>is registered afteromarchy-restart-shell.qs logafteromarchy-restart-shell.Invariants touched: "The app window is RECREATED on show, never re-mapped" (save workspace only from a user
movewindowv2). Fix 1 makes that behaviour actually happen; the documented invariant is unchanged. Fix 3 touches none.