pax b571c9a486 F11 round-trip: preserve image zoom/pan + popout window position
Two related preservation bugs around the popout's F11 fullscreen
toggle, both surfaced during the post-refactor verification sweep.

1. ImageViewer zoom/pan loss on resize

ImageViewer.resizeEvent unconditionally called _fit_to_view() on every
resize event. F11 enter resizes the widget to the full screen, F11
exit resizes it back to the windowed size — both fired _fit_to_view,
clobbering any explicit user zoom and offset. Same problem for manual
window drags and splitter moves.

Fix: in resizeEvent, compute the previous-size fit-to-view zoom from
event.oldSize() and compare to current _zoom. Only re-fit if the user
was at fit-to-view at the previous size (within a 0.001 epsilon —
tighter than any wheel/key zoom step). Otherwise leave _zoom and
_offset alone.

The first-resize case (no valid oldSize, e.g. initial layout) still
defaults to fit, matching the original behavior for fresh widgets.

2. Popout window position lost on F11 round-trip

FullscreenPreview._enter_fullscreen captured _windowed_geometry but
the F11-exit restore goes through `_viewport` (the persistent center +
long_side that drives _fit_to_content). The drift detection in
_derive_viewport_for_fit only updates _viewport when
_last_dispatched_rect is set AND a fit is being computed — neither
path catches the "user dragged the popout with Super+drag and then
immediately pressed F11" sequence:

  - Hyprland Super+drag does NOT fire Qt's moveEvent (xdg-toplevel
    doesn't expose absolute screen position to clients on Wayland),
    so Qt-side drift detection is dead on Hyprland.
  - The Hyprland-side drift detection in _derive_viewport_for_fit
    only fires inside a fit, and no fit is triggered between a drag
    and F11.
  - Result: _viewport still holds whatever it had before the drag —
    typically the saved-from-last-session geometry seeded by the
    first-fit one-shot at popout open.

When F11 exits, the deferred _fit_to_content reads the stale viewport
and restores the popout to the *previously seeded* position instead of
where the user actually had it.

Fix: in _enter_fullscreen, after capturing _windowed_geometry, also
write the current windowed state into self._viewport directly. The
viewport then holds the actual pre-fullscreen position regardless of
how it got there (drag, drag+nav, drag+F11, etc.), and F11 exit's
restore reads it correctly.

Bundled into one commit because both fixes are "F11 round-trip should
preserve where the user was" — the image fix preserves content state
(zoom/pan), the popout fix preserves window state (position). Same
theme, related root cause class. Bisecting one without the other
would be misleading.

Verified manually:
  - image: scroll-zoom + drag pan + F11 + F11 → zoom and pan preserved
  - image: untouched zoom + F11 + F11 → still fits to view
  - image: scroll-zoom + manual window resize → zoom preserved
  - popout: Super+drag to a new position + F11 + F11 → lands at the
    dragged position, not at the saved-from-last-session position
  - popout: same sequence on a video post → same result (videos don't
    have zoom/pan, but the window-position fix applies to all media)
2026-04-08 16:19:35 -05:00
..