x11: correct position coordinates if mpv was launched with --fs

If mpv is launched with --fs, the x11 code tries to reset the size and
position of the window when the fullscreen exits. This has bad behavior
with multiple monitors because the saved nofsrc is not reliable in many
situations. Particularly if the window manager moves the fullscreen
window somewhere else while mpv is fullscreen. The result will be that
exiting fullscreen always goes back to screen 0.

Fix this by translating the rc coordinates of the nofsrc rc to the new
monitor when we're leaving fullscreen from an initial --fs case. By
giving get_current_display a specific rc, we can return what xrandr
display the coordinates are associated with and decide if the nofsrc
should be translated to its new location. After that bit of math, the
usual move/resize logic takes care of the rest but this time it actually
works off of the correct position. Fixes #14226.
This commit is contained in:
Dudemanguy 2024-05-25 13:49:05 -05:00
parent 7ff6cf807c
commit 52bdeb07a1
2 changed files with 27 additions and 3 deletions

View File

@ -578,13 +578,13 @@ static void vo_x11_update_screeninfo(struct vo *vo)
} }
} }
static struct xrandr_display *get_current_display(struct vo *vo) static struct xrandr_display *get_xrandr_display(struct vo *vo, struct mp_rect rc)
{ {
struct vo_x11_state *x11 = vo->x11; struct vo_x11_state *x11 = vo->x11;
struct xrandr_display *selected_disp = NULL; struct xrandr_display *selected_disp = NULL;
for (int n = 0; n < x11->num_displays; n++) { for (int n = 0; n < x11->num_displays; n++) {
struct xrandr_display *disp = &x11->displays[n]; struct xrandr_display *disp = &x11->displays[n];
disp->overlaps = rc_overlaps(disp->rc, x11->winrc); disp->overlaps = rc_overlaps(disp->rc, rc);
if (disp->overlaps && (!selected_disp || disp->fps < selected_disp->fps)) if (disp->overlaps && (!selected_disp || disp->fps < selected_disp->fps))
selected_disp = disp; selected_disp = disp;
} }
@ -1262,6 +1262,7 @@ void vo_x11_check_events(struct vo *vo)
if (x11->window == None) if (x11->window == None)
break; break;
vo_x11_update_geometry(vo); vo_x11_update_geometry(vo);
vo_x11_update_screeninfo(vo);
if (x11->parent && Event.xconfigure.window == x11->parent) { if (x11->parent && Event.xconfigure.window == x11->parent) {
MP_TRACE(x11, "adjusting embedded window position\n"); MP_TRACE(x11, "adjusting embedded window position\n");
XMoveResizeWindow(x11->display, x11->window, XMoveResizeWindow(x11->display, x11->window,
@ -1665,6 +1666,7 @@ static void vo_x11_map_window(struct vo *vo, struct mp_rect rc)
XChangeProperty(x11->display, x11->window, XA(x11, _NET_WM_STATE), XA_ATOM, XChangeProperty(x11->display, x11->window, XA(x11, _NET_WM_STATE), XA_ATOM,
32, PropModeAppend, (unsigned char *)&state, 1); 32, PropModeAppend, (unsigned char *)&state, 1);
x11->fs = 1; x11->fs = 1;
x11->init_fs = true;
// The "saved" positions are bogus, so reset them when leaving FS again. // The "saved" positions are bogus, so reset them when leaving FS again.
x11->size_changed_during_fs = true; x11->size_changed_during_fs = true;
x11->pos_changed_during_fs = true; x11->pos_changed_during_fs = true;
@ -1932,7 +1934,7 @@ static void vo_x11_update_geometry(struct vo *vo)
&x, &y, &dummy_win); &x, &y, &dummy_win);
x11->winrc = (struct mp_rect){x, y, x + w, y + h}; x11->winrc = (struct mp_rect){x, y, x + w, y + h};
} }
struct xrandr_display *disp = get_current_display(vo); struct xrandr_display *disp = get_xrandr_display(vo, x11->winrc);
// Try to fallback to something reasonable if we have no disp yet // Try to fallback to something reasonable if we have no disp yet
if (!disp) { if (!disp) {
int screen = vo_x11_select_screen(vo); int screen = vo_x11_select_screen(vo);
@ -1985,6 +1987,26 @@ static void vo_x11_fullscreen(struct vo *vo)
rc.x1 -= 1; rc.x1 -= 1;
rc.y1 -= 1; rc.y1 -= 1;
} }
// If launched with --fs and the fs screen is different than
// nofsrc, try to translate nofsrc to the fs screen.
if (x11->init_fs) {
struct xrandr_display *fs_disp = get_xrandr_display(vo, x11->winrc);
struct xrandr_display *nofs_disp = get_xrandr_display(vo, x11->nofsrc);
if (fs_disp && nofs_disp && fs_disp->screen != nofs_disp->screen) {
int old_w = mp_rect_w(x11->nofsrc);
int old_h = mp_rect_h(x11->nofsrc);
int new_x = (mp_rect_w(fs_disp->rc) - old_w) / 2 + fs_disp->rc.x0;
int new_y = (mp_rect_h(fs_disp->rc) - old_h) / 2 + fs_disp->rc.y0;
x11->nofsrc.x0 = new_x;
x11->nofsrc.x1 = new_x + old_w;
x11->nofsrc.y0 = new_y;
x11->nofsrc.y1 = new_y + old_h;
rc = x11->nofsrc;
}
x11->init_fs = false;
}
vo_x11_move_resize(vo, x11->pos_changed_during_fs, vo_x11_move_resize(vo, x11->pos_changed_during_fs,
x11->size_changed_during_fs, rc); x11->size_changed_during_fs, rc);
} }

View File

@ -93,6 +93,8 @@ struct vo_x11_state {
bool pseudo_mapped; // not necessarily mapped, but known window size bool pseudo_mapped; // not necessarily mapped, but known window size
int fs; // whether we assume the window is in fullscreen mode int fs; // whether we assume the window is in fullscreen mode
bool init_fs; // whether mpv was launched with --fs
bool mouse_cursor_visible; // whether we want the cursor to be visible (only bool mouse_cursor_visible; // whether we want the cursor to be visible (only
// takes effect when the window is focused) // takes effect when the window is focused)
bool mouse_cursor_set; // whether the cursor is *currently* *hidden* bool mouse_cursor_set; // whether the cursor is *currently* *hidden*