fix(desktop): rescale cx/cy in rebaseForCurrentOutputs on output size change - #4272
fix(desktop): rescale cx/cy in rebaseForCurrentOutputs on output size change#4272kvnloo wants to merge 1 commit into
Conversation
… change rebaseForCurrentOutputs only backfilled placementWidth/Height, so exitEdit locked 1366-centered widgets behind a 1920 placement size and skipped remapForOutputChange. Mirror remapForOutputChange's rescale before writing the current output size. Refs noctalia-dev#4123
Both reproductions in #4123 have placement_* == current output size:
The new guard is widget.placementWidth != width || widget.placementHeight != height. With placement already equal to the live size, the rescale never fires. The symptom is unchanged. The actual corruption path is the backfill branch of remapForOutputChange (desktop_widget_layout.h:91-96): coordinates authored under an unknown older geometry get stamped with the current size and no rescale is possible, because the old basis is not recorded anywhere. The reporter says as much ("no deterministic retroactive fix"). rebaseForCurrentOutputs is not on that path: it runs only from exitEdit (desktop_widgets_controller.cpp:347, lockscreen_widgets_controller.cpp:238). Load and hotplug already go through remapForOutputChange (desktop_widgets_controller.cpp:104,262-264;
cx/cy are absolute logical coordinates; placementWidth/Height records the basis they were authored in Regression A: cross-output drag (multi-monitor, differing logical sizes)updateDrag reassigns state->outputName and rewrites cx/cy into the target output's local space Drag a widget from 3840x2160 to 1920x1080 and drop it centered (cx = 960, basis still 3840): cx = 960 × ────── = 480 The widget teleports to the quarter line on exit, and saveSnapshotToConfig() (desktop_widgets_controller.cpp:350) persists it. Deterministic on any multi-output setup where logical sizes differ. Regression B: geometry change while the editor is openDesktopWidgetsEditor::onOutputChange() (desktop_widgets_editor.cpp:2626-2632) only calls syncSurfaces() + requestLayout(); it does not remap its own snapshot. The controller's remapForOutputChange at :262-264 operates on m_snapshot, which exitEdit then throws away (m_snapshot = m_editor->snapshot(), :345). So the editor's copy holds live coordinates with a stale basis: scale 1→2 on a 3440-wide output, exit edit, every widget's cx is halved relative to where it is drawn.
"Replica of the function body" tests the patch's own arithmetic assumption, not the behavior of the shell; the file isn't Constructive alternative The real invariant to restore is "recorded basis always matches the coordinates":
Also worth flagging, the design detail that made this patch look correct (cx/cy are live post-editor, only |
Summary
Make
rebaseForCurrentOutputsrescale widgetcx/cywhen placement size differs from the current output size, then write the new placement size — same arithmetic asremapForOutputChange.Motivation
Origin issue #4123: after
exitEdit, a widget centered on a 1366-wide output could be stored behindplacement_width=1920, locking the old center forever because rebase only backfilled size without rescaling coordinates.Type of Change
Related Issue
Related to #4123
Testing
rebase_placement_test.cpp): baseline assignment-only failscx must rescale 1366 -> 1920(exit 1); candidate rescale then write size passes (exit 0).placementWidth==0records size without inventing a rescale.src/shell/desktop/desktop_widget_layout.h(rebaseForCurrentOutputsonly). Does not touch settings.toml shadowing (open feat(config): warn when settings.toml shadows hand-authored widget placement keys #4124).Checklist
CONTRIBUTING.md.just formatwith clang-format v22+ installed, or this PR has no code changes.docs/user/when this PR changes documented behavior or configuration, or this PR does not require documentation changes.assets/translations/en.json, or this PR adds no new user-facing strings.Additional Notes
Prior PR #4236 was closed for an incomplete template body. Same candidate SHA
a14172fcb227716ce7ca308669f5e8ff95c1df2e.