summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDudemanguy <random342@airmail.cc>2020-08-18 12:55:01 -0500
committerDudemanguy <random342@airmail.cc>2020-08-20 01:34:45 +0000
commitdb0f9fab67af4776ec82dd491413fe642fb2670a (patch)
treeac02168707ae8df43d7372df93142ed08ff85543
parentffa9aaa2e458dcac3658a16c4d1fb14755de0ebd (diff)
downloadmpv-db0f9fab67af4776ec82dd491413fe642fb2670a.tar.bz2
mpv-db0f9fab67af4776ec82dd491413fe642fb2670a.tar.xz
wayland: refactor geometry/window handling
The original goal was to simplify all this logic to make it less fragile and breaky. Unfortunately, that didn't exactly happen and things might actually be more complicated in some ways (well in other ways it's simplier). There's a lot of negotiation back and forth between the client and the compositor regarding sizes. The client (aka mpv) can do a resize on its own. But also the compositor can request its own resize (which we should be nice and listen to of course). The older method had a lot of breakfalls/edgecases that were gradually patched up as time went on, but that approach is really fragile. This refactor should, hopefully, be on a more solid foundation. Don't call any of the xdg toplevel state changing functions (fullscreen, maximized, etc.) directly. Use the toggle wrapper functions. These signal that the state was changed which is later handled in the toplevel listener. Introduce a new vdparams variable that stores the actual dimensions of the video. This does create some new (but neccesary) complexity. wl->vdparams stores what the actual dimensions of the video are (according to mpv). wl->window_size stores the last size of the window (so it includes any manual resizes for instance). wl->geometry is the actual size of the output that gets displayed on the screen.
-rw-r--r--video/out/wayland_common.c211
-rw-r--r--video/out/wayland_common.h5
2 files changed, 112 insertions, 104 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index 4a9771a25e..ad752218f9 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -155,10 +155,9 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
wl->mouse_unscaled_x = sx;
wl->mouse_unscaled_y = sy;
- if (!wl->state_changed) {
+ if (!wl->toplevel_configured)
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
- }
- wl->state_changed = false;
+ wl->toplevel_configured = false;
}
static void window_move(struct vo_wayland_state *wl, uint32_t serial)
@@ -950,15 +949,13 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
struct mp_vo_opts *vo_opts = wl->vo_opts;
struct mp_rect old_geometry = wl->geometry;
- bool found_fullscreen = false;
- bool found_maximized = false;
- bool is_maximized = vo_opts->window_maximized;
- bool is_fullscreen = vo_opts->fullscreen;
+ bool is_maximized = false;
+ bool is_fullscreen = false;
enum xdg_toplevel_state *state;
wl_array_for_each(state, states) {
switch (*state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
- found_fullscreen = true;
+ is_fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
wl->pending_vo_events |= VO_EVENT_LIVE_RESIZING;
@@ -978,62 +975,72 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
case XDG_TOPLEVEL_STATE_MAXIMIZED:
- found_maximized = true;
+ is_maximized = true;
break;
}
}
- is_maximized = found_maximized;
- is_fullscreen = found_fullscreen;
- vo_opts->fullscreen = is_fullscreen;
- m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->fullscreen);
- vo_opts->window_maximized = is_maximized;
- m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->window_maximized);
+ if (vo_opts->fullscreen != is_fullscreen) {
+ wl->state_change = true;
+ vo_opts->fullscreen = is_fullscreen;
+ m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->fullscreen);
+ }
+
+ if (vo_opts->window_maximized != is_maximized) {
+ wl->state_change = true;
+ vo_opts->window_maximized = is_maximized;
+ m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->window_maximized);
+ }
+
+ if (!(wl->pending_vo_events & VO_EVENT_LIVE_RESIZING))
+ vo_query_and_reset_events(wl->vo, VO_EVENT_LIVE_RESIZING);
int old_toplevel_width = wl->toplevel_width;
int old_toplevel_height = wl->toplevel_height;
wl->toplevel_width = width;
wl->toplevel_height = height;
- if (!(wl->pending_vo_events & VO_EVENT_LIVE_RESIZING))
- vo_query_and_reset_events(wl->vo, VO_EVENT_LIVE_RESIZING);
+ if (wl->state_change) {
+ if (!is_fullscreen && !is_maximized) {
+ wl->geometry = wl->window_size;
+ wl->state_change = false;
+ goto resize;
+ }
+ }
if (old_toplevel_width == wl->toplevel_width && old_toplevel_height == wl->toplevel_height)
return;
- if (width > 0 && height > 0) {
- if (!is_fullscreen && !is_maximized) {
- if (wl->vo_opts->keepaspect && wl->vo_opts->keepaspect_window) {
- if (abs(wl->toplevel_width - old_toplevel_width) > abs(wl->toplevel_height - old_toplevel_height)) {
- double scale_factor = (double)width / wl->reduced_width;
- width = wl->reduced_width * scale_factor;
- } else {
- double scale_factor = (double)height / wl->reduced_height;
- height = wl->reduced_height * scale_factor;
- }
+ if (!is_fullscreen && !is_maximized) {
+ if (vo_opts->keepaspect && vo_opts->keepaspect_window) {
+ if (abs(wl->toplevel_width - old_toplevel_width) > abs(wl->toplevel_height - old_toplevel_height)) {
+ double scale_factor = (double)width / wl->reduced_width;
+ width = wl->reduced_width * scale_factor;
+ } else {
+ double scale_factor = (double)height / wl->reduced_height;
+ height = wl->reduced_height * scale_factor;
}
- wl->window_size.x0 = 0;
- wl->window_size.y0 = 0;
- wl->window_size.x1 = width;
- wl->window_size.y1 = height;
}
- wl->geometry.x0 = 0;
- wl->geometry.y0 = 0;
- wl->geometry.x1 = width;
- wl->geometry.y1 = height;
- } else {
- wl->geometry = wl->window_size;
+ wl->window_size.x0 = 0;
+ wl->window_size.y0 = 0;
+ wl->window_size.x1 = width;
+ wl->window_size.y1 = height;
}
+ wl->geometry.x0 = 0;
+ wl->geometry.y0 = 0;
+ wl->geometry.x1 = width;
+ wl->geometry.y1 = height;
if (mp_rect_equals(&old_geometry, &wl->geometry))
return;
+resize:
MP_VERBOSE(wl, "Resizing due to xdg from %ix%i to %ix%i\n",
mp_rect_w(old_geometry)*wl->scaling, mp_rect_h(old_geometry)*wl->scaling,
mp_rect_w(wl->geometry)*wl->scaling, mp_rect_h(wl->geometry)*wl->scaling);
wl->pending_vo_events |= VO_EVENT_RESIZE;
- wl->state_changed = true;
+ wl->toplevel_configured = true;
}
static void handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
@@ -1309,6 +1316,41 @@ static bool find_output(struct vo_wayland_state *wl, int index)
return 0;
}
+static void toggle_fullscreen(struct vo_wayland_state *wl)
+{
+ if (!wl->xdg_toplevel)
+ return;
+ wl->state_change = true;
+ if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id < 0) {
+ xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
+ } else if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id >= 0) {
+ find_output(wl, wl->vo_opts->fsscreen_id);
+ xdg_toplevel_set_fullscreen(wl->xdg_toplevel, wl->current_output->output);
+ } else {
+ xdg_toplevel_unset_fullscreen(wl->xdg_toplevel);
+ }
+}
+
+static void toggle_maximized(struct vo_wayland_state *wl)
+{
+ if (!wl->xdg_toplevel)
+ return;
+ wl->state_change = true;
+ if (wl->vo_opts->window_maximized) {
+ xdg_toplevel_set_maximized(wl->xdg_toplevel);
+ } else {
+ xdg_toplevel_unset_maximized(wl->xdg_toplevel);
+ }
+}
+
+static void do_minimize(struct vo_wayland_state *wl)
+{
+ if (!wl->xdg_toplevel)
+ return;
+ if (wl->vo_opts->window_minimized)
+ xdg_toplevel_set_minimized(wl->xdg_toplevel);
+}
+
static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b) {
// euclidean algorithm
int larger;
@@ -1331,6 +1373,7 @@ static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b) {
int vo_wayland_reconfig(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wl;
+ bool configure = false;
MP_VERBOSE(wl, "Reconfiguring!\n");
@@ -1343,6 +1386,7 @@ int vo_wayland_reconfig(struct vo *vo)
if (!wl->vo_opts->hidpi_window_scale)
wl->current_output->scale = 1;
wl->scaling = wl->current_output->scale;
+ configure = true;
}
struct vo_win_geometry geo;
@@ -1350,46 +1394,41 @@ int vo_wayland_reconfig(struct vo *vo)
vo_calc_window_geometry(vo, &screenrc, &geo);
vo_apply_window_geometry(vo, &geo);
- if (!wl->configured || !wl->vo_opts->window_maximized) {
- wl->geometry.x0 = 0;
- wl->geometry.y0 = 0;
- wl->geometry.x1 = vo->dwidth / wl->scaling;
- wl->geometry.y1 = vo->dheight / wl->scaling;
- wl->window_size = wl->geometry;
- }
-
greatest_common_divisor(wl, vo->dwidth, vo->dheight);
wl->reduced_width = vo->dwidth / wl->gcd;
wl->reduced_height = vo->dheight / wl->gcd;
- if (wl->vo_opts->fullscreen) {
- wl->geometry.x0 = 0;
- wl->geometry.y0 = 0;
- wl->geometry.x1 = mp_rect_w(wl->current_output->geometry) / wl->scaling;
- wl->geometry.y1 = mp_rect_h(wl->current_output->geometry) / wl->scaling;
- if (wl->vo_opts->fsscreen_id < 0) {
- xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
- } else if (wl->vo_opts->fsscreen_id >= 0) {
- xdg_toplevel_set_fullscreen(wl->xdg_toplevel, wl->current_output->output);
- }
+ wl->vdparams.x0 = 0;
+ wl->vdparams.y0 = 0;
+ wl->vdparams.x1 = vo->dwidth / wl->scaling;
+ wl->vdparams.y1 = vo->dheight / wl->scaling;
+ if (wl->vo_opts->keepaspect && wl->vo_opts->keepaspect_window) {
+ wl->window_size = wl->vdparams;
}
+ if (wl->vo_opts->fullscreen)
+ toggle_fullscreen(wl);
+
if (wl->vo_opts->window_maximized)
- xdg_toplevel_set_maximized(wl->xdg_toplevel);
+ toggle_maximized(wl);
if (wl->vo_opts->window_minimized)
- xdg_toplevel_set_minimized(wl->xdg_toplevel);
+ do_minimize(wl);
wl_surface_set_buffer_scale(wl->surface, wl->scaling);
wl_surface_commit(wl->surface);
- wl->pending_vo_events |= VO_EVENT_RESIZE;
- if (!wl->configured) {
- if (spawn_cursor(wl))
- return false;
+
+ if (configure) {
+ wl->window_size = wl->vdparams;
+ wl->geometry = wl->vdparams;
wl_display_roundtrip(wl->display);
- wl->configured = true;
}
+ if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized)
+ wl->geometry = wl->window_size;
+
+ wl->pending_vo_events |= VO_EVENT_RESIZE;
+
return true;
}
@@ -1411,38 +1450,6 @@ static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state)
return VO_TRUE;
}
-static void toggle_fullscreen(struct vo_wayland_state *wl)
-{
- if (!wl->xdg_toplevel)
- return;
- if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id < 0) {
- xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
- } else if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id >= 0) {
- find_output(wl, wl->vo_opts->fsscreen_id);
- xdg_toplevel_set_fullscreen(wl->xdg_toplevel, wl->current_output->output);
- } else {
- xdg_toplevel_unset_fullscreen(wl->xdg_toplevel);
- }
-}
-
-static void toggle_maximized(struct vo_wayland_state *wl)
-{
- if (!wl->xdg_toplevel)
- return;
- if (wl->vo_opts->window_maximized)
- xdg_toplevel_set_maximized(wl->xdg_toplevel);
- else
- xdg_toplevel_unset_maximized(wl->xdg_toplevel);
-}
-
-static void do_minimize(struct vo_wayland_state *wl)
-{
- if (!wl->xdg_toplevel)
- return;
- if (wl->vo_opts->window_minimized)
- xdg_toplevel_set_minimized(wl->xdg_toplevel);
-}
-
static int update_window_title(struct vo_wayland_state *wl, const char *title)
{
if (!wl->xdg_toplevel)
@@ -1543,18 +1550,18 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
}
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
int *s = arg;
- s[0] = mp_rect_w(wl->geometry)*wl->scaling;
- s[1] = mp_rect_h(wl->geometry)*wl->scaling;
+ s[0] = mp_rect_w(wl->geometry) * wl->scaling;
+ s[1] = mp_rect_h(wl->geometry) * wl->scaling;
return VO_TRUE;
}
case VOCTRL_SET_UNFS_WINDOW_SIZE: {
int *s = arg;
+ wl->window_size.x0 = 0;
+ wl->window_size.y0 = 0;
+ wl->window_size.x1 = s[0] / wl->scaling;
+ wl->window_size.y1 = s[1] / wl->scaling;
if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) {
- wl->geometry.x0 = 0;
- wl->geometry.y0 = 0;
- wl->geometry.x1 = s[0]/wl->scaling;
- wl->geometry.y1 = s[1]/wl->scaling;
- wl->window_size = wl->geometry;
+ wl->geometry = wl->window_size;
wl->pending_vo_events |= VO_EVENT_RESIZE;
}
return VO_TRUE;
diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h
index 895db3393d..7748627b29 100644
--- a/video/out/wayland_common.h
+++ b/video/out/wayland_common.h
@@ -70,12 +70,13 @@ struct vo_wayland_state {
/* State */
struct mp_rect geometry;
struct mp_rect window_size;
+ struct mp_rect vdparams;
int gcd;
int reduced_width;
int reduced_height;
- bool configured;
bool frame_wait;
- bool state_changed;
+ bool state_change;
+ bool toplevel_configured;
int wakeup_pipe[2];
int pending_vo_events;
int mouse_x;