Skip to content

mac/window: fix vertical recentering on non-main screens - #18828

Open
zatlocal wants to merge 1 commit into
mpv-player:masterfrom
zatlocal:mac-window-recenter-fix
Open

zatlocal wants to merge 1 commit into
mpv-player:masterfrom
zatlocal:mac-window-recenter-fix

Conversation

@zatlocal

Copy link
Copy Markdown

constrainFrameRect recenters the window vertically when it shrinks from taller than its screen's visible frame to shorter than it. The new origin was (vf.height - nf.height) / 2, which is only correct for a screen whose visible frame starts at y = 0 (the main screen). All other checks in the function are screen relative.

On any other screen the window jumps to the main screen's coordinate range, usually a different display. The top bound check then clamps it to that new screen, so programmatic frame changes (e.g. window managers via the accessibility API) cannot move it back.

Example, screen stacked two screens above the main one (visible frame y = 3600, height = 1800), window resized from 1824 to 1530 height:

origin.y result
before (1800 - 1530) / 2 = 135 window on main screen
after 3600 + (1800 - 1530) / 2 = 3735 window stays on its screen

To reproduce: on a multi monitor setup, place a window on a non-main screen, make it taller than that screen's visible frame, then set a shorter frame via the accessibility API (e.g. Hammerspoon hs.window:setFrame).

Fix: offset the recentered origin by vf.minY.

constrainFrameRect recenters the window vertically when it shrinks from
taller than the visible frame of its screen to shorter than it, to
counter the 'snap to top' behaviour. the new origin was calculated as
(vf.height - nf.height) / 2, which is only correct for a screen whose
visible frame starts at y = 0, i.e. the main screen. every other check
in this function uses screen relative coordinates (vf.maxY, vf.minY).

on any other screen the window was moved to the main screen's
coordinate range instead, usually onto a different display. since the
top bound check clamps the window to its new screen's visible frame,
it could not be moved back by programmatic frame changes afterwards
(e.g. window managers using the accessibility API) and had to be
dragged back manually.

example, with a screen stacked two screens above the main one:
  visible frame: y = 3600 (cocoa coordinates), height = 1800
  window resized from 1824 to 1530 height
  before: origin.y = (1800 - 1530) / 2 = 135, window on the main screen
  after:  origin.y = 3600 + (1800 - 1530) / 2 = 3735, window stays

reproduce on a multi monitor setup: place a window on a screen other
than the main one, make it taller than that screen's visible frame and
then set a frame shorter than it via the accessibility API (e.g.
Hammerspoon's hs.window:setFrame).

fix this by offsetting the recentered origin by the visible frame's
minY.
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.

1 participant