Add taskbar monitor picker to the context menu#65
Open
svenbledt wants to merge 3 commits into
Open
Conversation
On multi-monitor setups the widget could only be moved between taskbars by dragging it, which is hard to discover. This adds a "Display on" submenu to the right-click context menu (shared by the widget and the tray icon) that lists each detected taskbar as "Monitor N", tags the primary display, and checkmarks the current one. Selecting an entry re-embeds the widget on that monitor's taskbar and persists the choice. The submenu is omitted on single-monitor systems. Selection reuses the existing positional taskbar_index and attach_to_taskbar path, so there is no settings-schema change; if the widget was hidden, picking a monitor shows it there. New menu command IDs use the 90..=105 range to avoid colliding with the existing tray toggle ID. Strings are localized across all 11 supported languages.
The monitor picker persisted only a positional taskbar_index. Taskbars are ordered by screen position, but the *set* is not stable: when a fullscreen app hides or recreates a monitor's taskbar, that taskbar drops out of (and later returns to) the enumeration, so a given index maps to a different physical monitor. Any re-attach that resolved the saved index against the changed set therefore moved the widget onto the wrong taskbar. A diagnostic capture showed exactly this: index=1 resolving to the right monitor with count=2, then to a middle monitor once count grew to 3. Identify the target monitor by its stable device name (szDevice, e.g. "\.\DISPLAY2") instead of list position: - find_taskbars() now records each taskbar's monitor device name. - attach_to_taskbar() prefers the saved device, falling back to the clamped index only when that monitor's taskbar is absent, and persists the resolved device. - The new taskbar_monitor setting carries the choice (index kept for back-compat / migration; existing settings upgrade on first attach). - The picker resolves the clicked entry to the device captured when the menu was built, and checkmarks by device rather than index. - On WM_DISPLAYCHANGE the widget re-homes to its saved monitor once that monitor's taskbar returns (e.g. after leaving fullscreen), only ever pulling toward the user's choice. Adds unit tests for the resolver covering the changed-set case.
The previous fix identified the target monitor by stable device name so a changing taskbar set could not move the widget. But attach_to_taskbar still persisted whatever monitor it *resolved to* into taskbar_monitor on every call — including automatic attaches (startup, WM_DISPLAYCHANGE re-home) that fell back to a different monitor because the chosen one's taskbar was temporarily absent (fullscreen app, monitor churn). That rewrote the user's saved choice with the fallback monitor. Two visible symptoms followed: the widget appeared to switch taskbars, and the picker's own checkmark / persisted setting silently moved to the wrong monitor, from which reattach_to_saved_monitor_if_needed could never bring it home because the saved intent itself was now gone. Treat the saved preference as the user's intent and only adopt a resolved monitor when: - the user explicitly picked it (picker click / drag), or - the resolve actually matched the saved preference, or - no preference was saved yet (legacy index-only migration). - resolve_taskbar_index() now also reports whether it matched the preferred device or fell back to the positional index. - New pure monitor_pref_after_attach() encodes the persist decision. - attach_to_taskbar() gains a persist_choice flag: picker and drag pass true, startup and display-change re-home pass false so a transient fallback can never clobber the saved monitor. Adds unit tests covering the fallback (must not overwrite), matched-keep, legacy migration, and user-choice-on-fallback cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On multi-monitor setups, the widget could previously only be moved to another monitor's taskbar by dragging it (and dragging is restricted to the divider handle), which is hard to discover. This PR adds an explicit "Display on" submenu to the right-click context menu so users can pick the monitor directly.
What changed
Implementation notes
taskbar_indexand the existingattach_to_taskbarre-embed path — no settings-schema change.MonitorFromRect+GetMonitorInfoW(MONITORINFOF_PRIMARY) against each taskbar rect; taskbar enumeration and sort order are unchanged, so the positional index stays consistent with the existing drag-to-move behavior.90..=105range to avoid colliding with the existing tray-toggle command ID.display_on,monitor,primary) are localized across all 11 supported languages.Testing
cargo buildandcargo testpass; a unit test covers the monitor label formatting (primary tagging and 1-based numbering).cargo clippyintroduces no new warnings.Scope
Deliberately out of scope: device-ID persistence that survives monitor re-arrangement, resolution labels, and auto-follow-cursor placement.