History

wayland: fix vertical resizing

Resizing in strictly the vertical direction has been broken forever on wayland. It's because of how the keepaspect calculation always resized with respect to the width. So if you moved the mouse strictly vertically with no change left/right, the mpv window would never change size since it just calculates with respect to the width that doesn't change. Fixing this is kind of weird and maybe someone should think of a better algorithm for preserving aspect ratio (we just multiply by the gcd basically), but whatever. You might naively try something like "resize with respect to what direction changes the most" at first, but this leads to very cludgy resizing since during a typical mouse dragging motion, it will flip constantly from "resize w/ respect to the width" and "resize w/ respect to the height". It "works" but it's really ugly and not worth it. The trick is to realize that we need to consider the resizing state as one continuous motion, choose a direction initially, stick to it throughout the entirety of the resize, and reset the relevant parameters after we finish the resize. This ensures the direction never unintuitively flips during a motion, but also allows for the strictly vertical case to still work. Might as well note it here in the commit, but mpv's resizing behavior technically violates xdg-shell. For the resizing event, "[t]he window geometry specified in the configure event is a maximum; the client cannot resize beyond it." Well, we do obviously go beyond the maximum in certain cases. For example consider resizing strictly horizontally. The width value increases from the compositor but not the height. Since mpv preserves aspect ratio by default, the height obviously must increase which will go over the prescribed bounds by the compositor. This happens before and after this commit, and I think everyone agrees is the desired behavior. With this commit, now vertical resizing works which violates xdg-shell in the same way. Before, it incidentally obeyed the protocol since it did not resize at all, but let's presume users expect the window to actually get bigger when they do a drag resize. *: https://wayland.app/protocols/xdg-shell#xdg_toplevel:enum:state:entry:resizing

Dudemanguy committed 2 years ago

Commit e6c536a1 parent 5edc8972 files · +43 −0Browse files

Unified · Split

2 files
  1. video/out/wayland_common.c +41 −0
  2. video/out/wayland_common.h +2 −0
video/out/wayland_common.c+41−0
@@ -66,6 +66,11 @@ · 65 unmodified lines
66#define WAYLAND_SCALE_FACTOR 120.066#define WAYLAND_SCALE_FACTOR 120.0
67 67
68 68
69enum resizing_constraint {
70 MP_WIDTH_CONSTRAINT = 1,
71 MP_HEIGHT_CONSTRAINT = 2,
72};
73
69static const struct mp_keymap keymap[] = {74static const struct mp_keymap keymap[] = {
70 /* Special keys */75 /* Special keys */
71 {XKB_KEY_Pause, MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},76 {XKB_KEY_Pause, MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},
@@ -1038,6 +1043,7 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, · 966 unmodified lines
1038 bool is_maximized = false;1043 bool is_maximized = false;
1039 bool is_fullscreen = false;1044 bool is_fullscreen = false;
1040 bool is_activated = false;1045 bool is_activated = false;
1046 bool is_resizing = false;
1041 bool is_suspended = false;1047 bool is_suspended = false;
1042 bool is_tiled = false;1048 bool is_tiled = false;
1043 enum xdg_toplevel_state *state;1049 enum xdg_toplevel_state *state;
@@ -1047,6 +1053,7 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, · 3 unmodified lines
1047 is_fullscreen = true;1053 is_fullscreen = true;
1048 break;1054 break;
1049 case XDG_TOPLEVEL_STATE_RESIZING:1055 case XDG_TOPLEVEL_STATE_RESIZING:
1056 is_resizing = true;
1050 break;1057 break;
1051 case XDG_TOPLEVEL_STATE_ACTIVATED:1058 case XDG_TOPLEVEL_STATE_ACTIVATED:
1052 is_activated = true;1059 is_activated = true;
@@ -1077,6 +1084,11 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, · 24 unmodified lines
1077 if (wl->hidden != is_suspended)1084 if (wl->hidden != is_suspended)
1078 wl->hidden = is_suspended;1085 wl->hidden = is_suspended;
1079 1086
1087 if (wl->resizing != is_resizing) {
1088 wl->resizing = is_resizing;
1089 wl->resizing_constraint = 0;
1090 }
1091
1080 if (opts->fullscreen != is_fullscreen) {1092 if (opts->fullscreen != is_fullscreen) {
1081 wl->state_change = wl->reconfigured;1093 wl->state_change = wl->reconfigured;
1082 opts->fullscreen = is_fullscreen;1094 opts->fullscreen = is_fullscreen;
@@ -1553,10 +1565,39 @@ static void apply_keepaspect(struct vo_wayland_state *wl, int *width, int *heigh · 470 unmodified lines
1553 if (!wl->opts->keepaspect)1565 if (!wl->opts->keepaspect)
1554 return;1566 return;
1555 1567
1568 int phys_width = handle_round(wl->scaling, *width);
1569 int phys_height = handle_round(wl->scaling, *height);
1570
1571 // Ensure that the size actually changes before we start trying to actually
1572 // calculate anything so the wrong constraint for the rezie isn't choosen.
1573 if (wl->resizing && !wl->resizing_constraint &&
1574 phys_width == mp_rect_w(wl->geometry) && phys_height == mp_rect_h(wl->geometry))
1575 return;
1576
1577 // We are doing a continuous resize (e.g. dragging with mouse), constrain the
1578 // aspect ratio against the height if the change is only in the height
1579 // coordinate.
1580 if (wl->resizing && !wl->resizing_constraint && phys_width == mp_rect_w(wl->geometry) &&
1581 phys_height != mp_rect_h(wl->geometry)) {
1582 wl->resizing_constraint = MP_HEIGHT_CONSTRAINT;
1583 } else if (!wl->resizing_constraint) {
1584 wl->resizing_constraint = MP_WIDTH_CONSTRAINT;
1585 }
1586
1587 if (wl->resizing_constraint == MP_HEIGHT_CONSTRAINT) {
1588 MPSWAP(int, *width, *height);
1589 MPSWAP(int, wl->reduced_width, wl->reduced_height);
1590 }
1591
1556 double scale_factor = (double)*width / wl->reduced_width;1592 double scale_factor = (double)*width / wl->reduced_width;
1557 *width = ceil(wl->reduced_width * scale_factor);1593 *width = ceil(wl->reduced_width * scale_factor);
1558 if (wl->opts->keepaspect_window)1594 if (wl->opts->keepaspect_window)
1559 *height = ceil(wl->reduced_height * scale_factor);1595 *height = ceil(wl->reduced_height * scale_factor);
1596
1597 if (wl->resizing_constraint == MP_HEIGHT_CONSTRAINT) {
1598 MPSWAP(int, *width, *height);
1599 MPSWAP(int, wl->reduced_width, wl->reduced_height);
1600 }
1560}1601}
1561 1602
1562static void free_dnd_data(struct vo_wayland_state *wl)1603static void free_dnd_data(struct vo_wayland_state *wl)
video/out/wayland_common.h+2−0
@@ -68,6 +68,7 @@ struct vo_wayland_state { · 67 unmodified lines
68 bool locked_size;68 bool locked_size;
69 bool need_rescale;69 bool need_rescale;
70 bool reconfigured;70 bool reconfigured;
71 bool resizing;
71 bool scale_configured;72 bool scale_configured;
72 bool state_change;73 bool state_change;
73 bool tiled;74 bool tiled;
@@ -79,6 +80,7 @@ struct vo_wayland_state { · 5 unmodified lines
79 int pending_scaling; // base 12080 int pending_scaling; // base 120
80 int scaling; // base 12081 int scaling; // base 120
81 double scaling_factor; // wl->scaling divided by 12082 double scaling_factor; // wl->scaling divided by 120
83 int resizing_constraint;
82 int timeout_count;84 int timeout_count;
83 int wakeup_pipe[2];85 int wakeup_pipe[2];
84 86

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t