summaryrefslogtreecommitdiffstats
path: root/video/out/wayland_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/wayland_common.c')
-rw-r--r--video/out/wayland_common.c1008
1 files changed, 663 insertions, 345 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index 589135f..4a86c21 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -56,6 +56,10 @@
#include "cursor-shape-v1.h"
#endif
+#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 21
+#define HAVE_WAYLAND_1_21
+#endif
+
#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 22
#define HAVE_WAYLAND_1_22
#endif
@@ -133,7 +137,8 @@ static const struct mp_keymap keymap[] = {
{XKB_KEY_XF86HomePage, MP_KEY_HOMEPAGE}, {XKB_KEY_XF86WWW, MP_KEY_WWW},
{XKB_KEY_XF86Mail, MP_KEY_MAIL}, {XKB_KEY_XF86Favorites, MP_KEY_FAVORITES},
{XKB_KEY_XF86Search, MP_KEY_SEARCH}, {XKB_KEY_XF86Sleep, MP_KEY_SLEEP},
- {XKB_KEY_XF86Back, MP_KEY_BACK}, {XKB_KEY_XF86Tools, MP_KEY_TOOLS},
+ {XKB_KEY_XF86Back, MP_KEY_GO_BACK}, {XKB_KEY_XF86Forward, MP_KEY_GO_FORWARD},
+ {XKB_KEY_XF86Tools, MP_KEY_TOOLS},
{XKB_KEY_XF86ZoomIn, MP_KEY_ZOOMIN}, {XKB_KEY_XF86ZoomOut, MP_KEY_ZOOMOUT},
{0, 0}
@@ -182,53 +187,93 @@ struct vo_wayland_output {
struct wl_list link;
};
+struct vo_wayland_seat {
+ struct vo_wayland_state *wl;
+ struct wl_seat *seat;
+ uint32_t id;
+ struct wl_keyboard *keyboard;
+ struct wl_pointer *pointer;
+ struct wl_touch *touch;
+ struct wl_data_device *dnd_ddev;
+ /* TODO: unvoid this if required wayland protocols is bumped to 1.32+ */
+ void *cursor_shape_device;
+ uint32_t pointer_enter_serial;
+ uint32_t pointer_button_serial;
+ struct xkb_keymap *xkb_keymap;
+ struct xkb_state *xkb_state;
+ uint32_t keyboard_code;
+ int mpkey;
+ int mpmod;
+ double axis_value_vertical;
+ int32_t axis_value120_vertical;
+ double axis_value_horizontal;
+ int32_t axis_value120_horizontal;
+ bool axis_value120_scroll;
+ bool has_keyboard_input;
+ struct wl_list link;
+};
+
+static bool single_output_spanned(struct vo_wayland_state *wl);
+
static int check_for_resize(struct vo_wayland_state *wl, int edge_pixels,
enum xdg_toplevel_resize_edge *edge);
-static int get_mods(struct vo_wayland_state *wl);
+static int get_mods(struct vo_wayland_seat *seat);
+static int greatest_common_divisor(int a, int b);
static int lookupkey(int key);
-static int set_cursor_visibility(struct vo_wayland_state *wl, bool on);
+static int set_cursor_visibility(struct vo_wayland_seat *s, bool on);
static int spawn_cursor(struct vo_wayland_state *wl);
static void add_feedback(struct vo_wayland_feedback_pool *fback_pool,
struct wp_presentation_feedback *fback);
-static void get_shape_device(struct vo_wayland_state *wl);
-static int greatest_common_divisor(int a, int b);
+static void apply_keepaspect(struct vo_wayland_state *wl, int *width, int *height);
+static void get_shape_device(struct vo_wayland_state *wl, struct vo_wayland_seat *s);
static void guess_focus(struct vo_wayland_state *wl);
-static void prepare_resize(struct vo_wayland_state *wl, int width, int height);
+static void prepare_resize(struct vo_wayland_state *wl);
static void remove_feedback(struct vo_wayland_feedback_pool *fback_pool,
struct wp_presentation_feedback *fback);
static void remove_output(struct vo_wayland_output *out);
+static void remove_seat(struct vo_wayland_seat *seat);
static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode);
static void rescale_geometry(struct vo_wayland_state *wl, double old_scale);
static void set_geometry(struct vo_wayland_state *wl, bool resize);
static void set_surface_scaling(struct vo_wayland_state *wl);
-static void window_move(struct vo_wayland_state *wl, uint32_t serial);
+static void update_output_scaling(struct vo_wayland_state *wl);
+static void update_output_geometry(struct vo_wayland_state *wl, struct mp_rect old_geometry,
+ struct mp_rect old_output_geometry);
/* Wayland listener boilerplate */
static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t sx, wl_fixed_t sy)
{
- struct vo_wayland_state *wl = data;
-
- wl->pointer = pointer;
- wl->pointer_id = serial;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
- set_cursor_visibility(wl, wl->cursor_visible);
+ s->pointer_enter_serial = serial;
+ set_cursor_visibility(s, wl->cursor_visible);
mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_ENTER);
+
+ wl->mouse_x = wl_fixed_to_int(sx) * wl->scaling;
+ wl->mouse_y = wl_fixed_to_int(sy) * wl->scaling;
+
+ if (!wl->toplevel_configured)
+ mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
+ wl->toplevel_configured = false;
}
static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_LEAVE);
}
static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
wl->mouse_x = wl_fixed_to_int(sx) * wl->scaling;
wl->mouse_y = wl_fixed_to_int(sy) * wl->scaling;
@@ -242,7 +287,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t state)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
state = state == WL_POINTER_BUTTON_STATE_PRESSED ? MP_KEY_STATE_DOWN
: MP_KEY_STATE_UP;
@@ -272,44 +318,106 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
}
if (button)
- mp_input_put_key(wl->vo->input_ctx, button | state | wl->mpmod);
+ mp_input_put_key(wl->vo->input_ctx, button | state | s->mpmod);
+ enum xdg_toplevel_resize_edge edges;
if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) &&
- !wl->locked_size && (button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN))
+ !wl->locked_size && (button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN) &&
+ !wl->vo_opts->border && check_for_resize(wl, wl->opts->edge_pixels_pointer, &edges))
{
- uint32_t edges;
// Implement an edge resize zone if there are no decorations
- if (!wl->vo_opts->border && check_for_resize(wl, wl->opts->edge_pixels_pointer, &edges)) {
- xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edges);
- } else {
- window_move(wl, serial);
- }
- // Explicitly send an UP event after the client finishes a move/resize
+ xdg_toplevel_resize(wl->xdg_toplevel, s->seat, serial, edges);
+ // Explicitly send an UP event after the client finishes a resize
mp_input_put_key(wl->vo->input_ctx, button | MP_KEY_STATE_UP);
+ } else if (state == MP_KEY_STATE_DOWN) {
+ // Save the serial and seat for voctrl-initialized dragging requests.
+ s->pointer_button_serial = serial;
+ wl->last_button_seat = s;
+ } else {
+ wl->last_button_seat = NULL;
}
}
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ switch (axis) {
+ case WL_POINTER_AXIS_VERTICAL_SCROLL:
+ s->axis_value_vertical += wl_fixed_to_double(value);
+ break;
+ case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
+ s->axis_value_horizontal += wl_fixed_to_double(value);
+ break;
+ }
+}
+
+static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
+{
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
+ double value_vertical, value_horizontal;
+ if (s->axis_value120_scroll) {
+ // Prefer axis_value120 if supported and the axis event is from mouse wheel.
+ value_vertical = s->axis_value120_vertical / 120.0;
+ value_horizontal = s->axis_value120_horizontal / 120.0;
+ } else {
+ // The axis value is specified in logical coordinates, but the exact value emitted
+ // by one mouse wheel click is unspecified. In practice, most compositors use either
+ // 10 (GNOME, Weston) or 15 (wlroots, same as libinput) as the value.
+ // Divide the value by 10 and clamp it between -1 and 1 so that mouse wheel clicks
+ // work as intended on all compositors while still allowing high resolution trackpads.
+ value_vertical = MPCLAMP(s->axis_value_vertical / 10.0, -1, 1);
+ value_horizontal = MPCLAMP(s->axis_value_horizontal / 10.0, -1, 1);
+ }
+
+ if (value_vertical > 0)
+ mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_DOWN | s->mpmod, +value_vertical);
+ if (value_vertical < 0)
+ mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP | s->mpmod, -value_vertical);
+ if (value_horizontal > 0)
+ mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_RIGHT | s->mpmod, +value_horizontal);
+ if (value_horizontal < 0)
+ mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT | s->mpmod, -value_horizontal);
+
+ s->axis_value120_scroll = false;
+ s->axis_value_vertical = 0;
+ s->axis_value_horizontal = 0;
+ s->axis_value120_vertical = 0;
+ s->axis_value120_horizontal = 0;
+}
+
+static void pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis_source)
+{
+}
+
+static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis)
+{
+}
+
+static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis, int32_t discrete)
+{
+}
- double val = wl_fixed_to_double(value) < 0 ? -1 : 1;
+#ifdef HAVE_WAYLAND_1_21
+static void pointer_handle_axis_value120(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis, int32_t value120)
+{
+ struct vo_wayland_seat *s = data;
+ s->axis_value120_scroll = true;
switch (axis) {
case WL_POINTER_AXIS_VERTICAL_SCROLL:
- if (value > 0)
- mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_DOWN | wl->mpmod, +val);
- if (value < 0)
- mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP | wl->mpmod, -val);
+ s->axis_value120_vertical += value120;
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
- if (value > 0)
- mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_RIGHT | wl->mpmod, +val);
- if (value < 0)
- mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT | wl->mpmod, -val);
+ s->axis_value120_horizontal += value120;
break;
}
}
+#endif
static const struct wl_pointer_listener pointer_listener = {
pointer_handle_enter,
@@ -317,40 +425,55 @@ static const struct wl_pointer_listener pointer_listener = {
pointer_handle_motion,
pointer_handle_button,
pointer_handle_axis,
+ pointer_handle_frame,
+ pointer_handle_axis_source,
+ pointer_handle_axis_stop,
+ pointer_handle_axis_discrete,
+#ifdef HAVE_WAYLAND_1_21
+ pointer_handle_axis_value120,
+#endif
};
static void touch_handle_down(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, struct wl_surface *surface,
int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
- enum xdg_toplevel_resize_edge edge;
- if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y)) {
- if (check_for_resize(wl, wl->opts->edge_pixels_touch, &edge)) {
- xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edge);
- } else {
- xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
- }
- }
-
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN);
+
+ enum xdg_toplevel_resize_edge edge;
+ if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) &&
+ !wl->locked_size && check_for_resize(wl, wl->opts->edge_pixels_touch, &edge))
+ {
+ xdg_toplevel_resize(wl->xdg_toplevel, s->seat, serial, edge);
+ // Explicitly send an UP event after the client finishes a resize
+ mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP);
+ } else {
+ // Save the serial and seat for voctrl-initialized dragging requests.
+ s->pointer_button_serial = serial;
+ wl->last_button_seat = s;
+ }
}
static void touch_handle_up(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, int32_t id)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP);
+ wl->last_button_seat = NULL;
}
static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
@@ -366,18 +489,31 @@ static void touch_handle_cancel(void *data, struct wl_touch *wl_touch)
{
}
+static void touch_handle_shape(void *data, struct wl_touch *wl_touch,
+ int32_t id, wl_fixed_t major, wl_fixed_t minor)
+{
+}
+
+static void touch_handle_orientation(void *data, struct wl_touch *wl_touch,
+ int32_t id, wl_fixed_t orientation)
+{
+}
+
static const struct wl_touch_listener touch_listener = {
touch_handle_down,
touch_handle_up,
touch_handle_motion,
touch_handle_frame,
touch_handle_cancel,
+ touch_handle_shape,
+ touch_handle_orientation,
};
static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
uint32_t format, int32_t fd, uint32_t size)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
char *map_str;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
@@ -391,23 +527,25 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
return;
}
- wl->xkb_keymap = xkb_keymap_new_from_buffer(wl->xkb_context, map_str,
- strnlen(map_str, size),
- XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+ if (!s->xkb_keymap)
+ s->xkb_keymap = xkb_keymap_new_from_buffer(wl->xkb_context, map_str,
+ strnlen(map_str, size),
+ XKB_KEYMAP_FORMAT_TEXT_V1, 0);
munmap(map_str, size);
close(fd);
- if (!wl->xkb_keymap) {
+ if (!s->xkb_keymap) {
MP_ERR(wl, "failed to compile keymap\n");
return;
}
- wl->xkb_state = xkb_state_new(wl->xkb_keymap);
- if (!wl->xkb_state) {
+ if (!s->xkb_state)
+ s->xkb_state = xkb_state_new(s->xkb_keymap);
+ if (!s->xkb_state) {
MP_ERR(wl, "failed to create XKB state\n");
- xkb_keymap_unref(wl->xkb_keymap);
- wl->xkb_keymap = NULL;
+ xkb_keymap_unref(s->xkb_keymap);
+ s->xkb_keymap = NULL;
return;
}
}
@@ -416,19 +554,21 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys)
{
- struct vo_wayland_state *wl = data;
- wl->has_keyboard_input = true;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
+ s->has_keyboard_input = true;
guess_focus(wl);
}
static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface)
{
- struct vo_wayland_state *wl = data;
- wl->has_keyboard_input = false;
- wl->keyboard_code = 0;
- wl->mpkey = 0;
- wl->mpmod = 0;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
+ s->has_keyboard_input = false;
+ s->keyboard_code = 0;
+ s->mpkey = 0;
+ s->mpmod = 0;
mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
guess_focus(wl);
}
@@ -437,30 +577,37 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
- wl->keyboard_code = key + 8;
- xkb_keysym_t sym = xkb_state_key_get_one_sym(wl->xkb_state, wl->keyboard_code);
+ s->keyboard_code = key + 8;
+ xkb_keysym_t sym = xkb_state_key_get_one_sym(s->xkb_state, s->keyboard_code);
int mpkey = lookupkey(sym);
state = state == WL_KEYBOARD_KEY_STATE_PRESSED ? MP_KEY_STATE_DOWN
: MP_KEY_STATE_UP;
if (mpkey) {
- mp_input_put_key(wl->vo->input_ctx, mpkey | state | wl->mpmod);
+ mp_input_put_key(wl->vo->input_ctx, mpkey | state | s->mpmod);
} else {
- char s[128];
- if (xkb_keysym_to_utf8(sym, s, sizeof(s)) > 0) {
- mp_input_put_key_utf8(wl->vo->input_ctx, state | wl->mpmod, bstr0(s));
+ char str[128];
+ if (xkb_keysym_to_utf8(sym, str, sizeof(str)) > 0) {
+ mp_input_put_key_utf8(wl->vo->input_ctx, state | s->mpmod, bstr0(str));
} else {
// Assume a modifier was pressed and handle it in the mod event instead.
+ // If a modifier is released before a regular key, also release that
+ // key to not activate it again by accident.
+ if (state == MP_KEY_STATE_UP) {
+ s->mpkey = 0;
+ mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
+ }
return;
}
}
if (state == MP_KEY_STATE_DOWN)
- wl->mpkey = mpkey;
+ s->mpkey = mpkey;
if (mpkey && state == MP_KEY_STATE_UP)
- wl->mpkey = 0;
+ s->mpkey = 0;
}
static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
@@ -468,21 +615,23 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboar
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
- if (wl->xkb_state) {
- xkb_state_update_mask(wl->xkb_state, mods_depressed, mods_latched,
+ if (s->xkb_state) {
+ xkb_state_update_mask(s->xkb_state, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
- wl->mpmod = get_mods(wl);
- if (wl->mpkey)
- mp_input_put_key(wl->vo->input_ctx, wl->mpkey | MP_KEY_STATE_DOWN | wl->mpmod);
+ s->mpmod = get_mods(s);
+ if (s->mpkey)
+ mp_input_put_key(wl->vo->input_ctx, s->mpkey | MP_KEY_STATE_DOWN | s->mpmod);
}
}
static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
int32_t rate, int32_t delay)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
if (wl->vo_opts->native_keyrepeat)
mp_input_set_repeat_info(wl->vo->input_ctx, rate, delay);
}
@@ -499,43 +648,50 @@ static const struct wl_keyboard_listener keyboard_listener = {
static void seat_handle_caps(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl->pointer) {
- wl->pointer = wl_seat_get_pointer(seat);
- get_shape_device(wl);
- wl_pointer_add_listener(wl->pointer, &pointer_listener, wl);
- } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->pointer) {
- wl_pointer_destroy(wl->pointer);
- wl->pointer = NULL;
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !s->pointer) {
+ s->pointer = wl_seat_get_pointer(seat);
+ get_shape_device(s->wl, s);
+ wl_pointer_add_listener(s->pointer, &pointer_listener, s);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && s->pointer) {
+ wl_pointer_destroy(s->pointer);
+ s->pointer = NULL;
}
- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl->keyboard) {
- wl->keyboard = wl_seat_get_keyboard(seat);
- wl_keyboard_add_listener(wl->keyboard, &keyboard_listener, wl);
- } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl->keyboard) {
- wl_keyboard_destroy(wl->keyboard);
- wl->keyboard = NULL;
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !s->keyboard) {
+ s->keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_add_listener(s->keyboard, &keyboard_listener, s);
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && s->keyboard) {
+ wl_keyboard_destroy(s->keyboard);
+ s->keyboard = NULL;
}
- if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wl->touch) {
- wl->touch = wl_seat_get_touch(seat);
- wl_touch_set_user_data(wl->touch, wl);
- wl_touch_add_listener(wl->touch, &touch_listener, wl);
- } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wl->touch) {
- wl_touch_destroy(wl->touch);
- wl->touch = NULL;
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !s->touch) {
+ s->touch = wl_seat_get_touch(seat);
+ wl_touch_set_user_data(s->touch, s);
+ wl_touch_add_listener(s->touch, &touch_listener, s);
+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && s->touch) {
+ wl_touch_destroy(s->touch);
+ s->touch = NULL;
}
}
+static void seat_handle_name(void *data, struct wl_seat *seat,
+ const char *name)
+{
+}
+
static const struct wl_seat_listener seat_listener = {
seat_handle_caps,
+ seat_handle_name,
};
static void data_offer_handle_offer(void *data, struct wl_data_offer *offer,
const char *mime_type)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
int score = mp_event_get_mime_type_score(wl->vo->input_ctx, mime_type);
if (score > wl->dnd_mime_score && wl->vo_opts->drag_and_drop != -2) {
wl->dnd_mime_score = score;
@@ -552,7 +708,8 @@ static void data_offer_source_actions(void *data, struct wl_data_offer *offer, u
static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
if (dnd_action && wl->vo_opts->drag_and_drop != -2) {
if (wl->vo_opts->drag_and_drop >= 0) {
wl->dnd_action = wl->vo_opts->drag_and_drop;
@@ -560,8 +717,14 @@ static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer, u
wl->dnd_action = dnd_action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ?
DND_REPLACE : DND_APPEND;
}
- MP_VERBOSE(wl, "DND action is %s\n",
- wl->dnd_action == DND_REPLACE ? "DND_REPLACE" : "DND_APPEND");
+
+ static const char * const dnd_action_names[] = {
+ [DND_REPLACE] = "DND_REPLACE",
+ [DND_APPEND] = "DND_APPEND",
+ [DND_INSERT_NEXT] = "DND_INSERT_NEXT",
+ };
+
+ MP_VERBOSE(wl, "DND action is %s\n", dnd_action_names[wl->dnd_action]);
}
}
@@ -574,12 +737,13 @@ static const struct wl_data_offer_listener data_offer_listener = {
static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_ddev,
struct wl_data_offer *id)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
if (wl->dnd_offer)
wl_data_offer_destroy(wl->dnd_offer);
wl->dnd_offer = id;
- wl_data_offer_add_listener(id, &data_offer_listener, wl);
+ wl_data_offer_add_listener(id, &data_offer_listener, s);
}
static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev,
@@ -587,7 +751,8 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev,
wl_fixed_t x, wl_fixed_t y,
struct wl_data_offer *id)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
if (wl->dnd_offer != id) {
MP_FATAL(wl, "DND offer ID mismatch!\n");
return;
@@ -605,7 +770,8 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev,
static void data_device_handle_leave(void *data, struct wl_data_device *wl_ddev)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
if (wl->dnd_offer) {
if (wl->dnd_fd != -1)
@@ -625,13 +791,15 @@ static void data_device_handle_leave(void *data, struct wl_data_device *wl_ddev)
static void data_device_handle_motion(void *data, struct wl_data_device *wl_ddev,
uint32_t time, wl_fixed_t x, wl_fixed_t y)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
wl_data_offer_accept(wl->dnd_offer, time, wl->dnd_mime_type);
}
static void data_device_handle_drop(void *data, struct wl_data_device *wl_ddev)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
int pipefd[2];
@@ -652,7 +820,8 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_ddev)
static void data_device_handle_selection(void *data, struct wl_data_device *wl_ddev,
struct wl_data_offer *id)
{
- struct vo_wayland_state *wl = data;
+ struct vo_wayland_seat *s = data;
+ struct vo_wayland_state *wl = s->wl;
if (wl->dnd_offer) {
wl_data_offer_destroy(wl->dnd_offer);
@@ -723,10 +892,8 @@ static void output_handle_done(void *data, struct wl_output *wl_output)
* geometry and scaling should be recalculated. */
if (wl->current_output && wl->current_output->output == wl_output) {
set_surface_scaling(wl);
- spawn_cursor(wl);
set_geometry(wl, false);
- prepare_resize(wl, 0, 0);
- wl->pending_vo_events |= VO_EVENT_DPI;
+ prepare_resize(wl);
}
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
@@ -775,36 +942,23 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
struct mp_rect old_geometry = wl->geometry;
wl->current_output = NULL;
+ int outputs = 0;
struct vo_wayland_output *o;
wl_list_for_each(o, &wl->output_list, link) {
if (o->output == output) {
wl->current_output = o;
- break;
+ wl->current_output->has_surface = true;
}
+ if (o->has_surface)
+ ++outputs;
}
- wl->current_output->has_surface = true;
- bool force_resize = false;
-
- if (!wl->fractional_scale_manager && wl_surface_get_version(wl_surface) < 6 &&
- wl->scaling != wl->current_output->scale)
- {
- set_surface_scaling(wl);
- spawn_cursor(wl);
- force_resize = true;
- wl->pending_vo_events |= VO_EVENT_DPI;
- }
-
- if (!mp_rect_equals(&old_output_geometry, &wl->current_output->geometry)) {
- set_geometry(wl, false);
- force_resize = true;
- }
-
- if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize)
- prepare_resize(wl, 0, 0);
+ if (outputs == 1)
+ update_output_geometry(wl, old_geometry, old_output_geometry);
MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %f, refresh rate = %f Hz\n",
- o->make, o->model, o->id, wl->scaling, o->refresh_rate);
+ wl->current_output->make, wl->current_output->model,
+ wl->current_output->id, wl->scaling, wl->current_output->refresh_rate);
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
}
@@ -813,15 +967,27 @@ static void surface_handle_leave(void *data, struct wl_surface *wl_surface,
struct wl_output *output)
{
struct vo_wayland_state *wl = data;
+ if (!wl->current_output)
+ return;
+ struct mp_rect old_output_geometry = wl->current_output->geometry;
+ struct mp_rect old_geometry = wl->geometry;
+
+ int outputs = 0;
struct vo_wayland_output *o;
wl_list_for_each(o, &wl->output_list, link) {
- if (o->output == output) {
+ if (o->output == output)
o->has_surface = false;
- wl->pending_vo_events |= VO_EVENT_WIN_STATE;
- return;
- }
+ if (o->has_surface)
+ ++outputs;
+ if (o->output != output && o->has_surface)
+ wl->current_output = o;
}
+
+ if (outputs == 1)
+ update_output_geometry(wl, old_geometry, old_output_geometry);
+
+ wl->pending_vo_events |= VO_EVENT_WIN_STATE;
}
#ifdef HAVE_WAYLAND_1_22
@@ -830,21 +996,20 @@ static void surface_handle_preferred_buffer_scale(void *data,
int32_t scale)
{
struct vo_wayland_state *wl = data;
- double old_scale = wl->scaling;
- if (wl->fractional_scale_manager)
+ if (wl->fractional_scale_manager || wl->scaling == scale)
return;
- // dmabuf_wayland is always wl->scaling = 1
- wl->scaling = !wl->using_dmabuf_wayland ? scale : 1;
+ wl->pending_scaling = scale;
+ wl->scale_configured = true;
MP_VERBOSE(wl, "Obtained preferred scale, %f, from the compositor.\n",
wl->scaling);
wl->pending_vo_events |= VO_EVENT_DPI;
- if (wl->current_output) {
- rescale_geometry(wl, old_scale);
- set_geometry(wl, false);
- prepare_resize(wl, 0, 0);
- }
+ wl->need_rescale = true;
+
+ // Update scaling now.
+ if (single_output_spanned(wl))
+ update_output_scaling(wl);
}
static void surface_handle_preferred_buffer_transform(void *data,
@@ -889,12 +1054,12 @@ 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;
- int old_toplevel_width = wl->toplevel_width;
- int old_toplevel_height = wl->toplevel_height;
- wl->toplevel_width = width;
- wl->toplevel_height = height;
+ if (width < 0 || height < 0) {
+ MP_WARN(wl, "Compositor sent negative width/height values. Treating them as zero.\n");
+ width = height = 0;
+ }
- if (!wl->configured) {
+ if (!wl->geometry_configured) {
/* Save initial window size if the compositor gives us a hint here. */
bool autofit_or_geometry = vo_opts->geometry.wh_valid || vo_opts->autofit.wh_valid ||
vo_opts->autofit_larger.wh_valid || vo_opts->autofit_smaller.wh_valid;
@@ -949,20 +1114,24 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
wl->hidden = is_suspended;
if (vo_opts->fullscreen != is_fullscreen) {
- wl->state_change = true;
+ wl->state_change = wl->reconfigured;
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;
+ wl->state_change = wl->reconfigured;
vo_opts->window_maximized = is_maximized;
m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->window_maximized);
}
+ if (!is_tiled && wl->tiled)
+ wl->state_change = wl->reconfigured;
+
wl->tiled = is_tiled;
wl->locked_size = is_fullscreen || is_maximized || is_tiled;
+ wl->reconfigured = false;
if (wl->requested_decoration)
request_decoration_mode(wl, wl->requested_decoration);
@@ -993,26 +1162,17 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
goto resize;
}
- if (old_toplevel_width == wl->toplevel_width &&
- old_toplevel_height == wl->toplevel_height)
- return;
-
if (!wl->locked_size) {
- if (vo_opts->keepaspect) {
- double scale_factor = (double)width / wl->reduced_width;
- width = ceil(wl->reduced_width * scale_factor);
- if (vo_opts->keepaspect_window)
- height = ceil(wl->reduced_height * scale_factor);
- }
+ apply_keepaspect(wl, &width, &height);
wl->window_size.x0 = 0;
wl->window_size.y0 = 0;
- wl->window_size.x1 = round(width * wl->scaling);
- wl->window_size.y1 = round(height * wl->scaling);
+ wl->window_size.x1 = lround(width * wl->scaling);
+ wl->window_size.y1 = lround(height * wl->scaling);
}
wl->geometry.x0 = 0;
wl->geometry.y0 = 0;
- wl->geometry.x1 = round(width * wl->scaling);
- wl->geometry.y1 = round(height * wl->scaling);
+ wl->geometry.x1 = lround(width * wl->scaling);
+ wl->geometry.y1 = lround(height * wl->scaling);
if (mp_rect_equals(&old_geometry, &wl->geometry))
return;
@@ -1022,7 +1182,7 @@ resize:
mp_rect_w(old_geometry), mp_rect_h(old_geometry),
mp_rect_w(wl->geometry), mp_rect_h(wl->geometry));
- prepare_resize(wl, width, height);
+ prepare_resize(wl);
wl->toplevel_configured = true;
}
@@ -1062,18 +1222,19 @@ static void preferred_scale(void *data,
uint32_t scale)
{
struct vo_wayland_state *wl = data;
- double old_scale = wl->scaling;
+ double new_scale = (double)scale / 120;
+ if (wl->scaling == new_scale)
+ return;
- // dmabuf_wayland is always wl->scaling = 1
- wl->scaling = !wl->using_dmabuf_wayland ? (double)scale / 120 : 1;
+ wl->pending_scaling = new_scale;
+ wl->scale_configured = true;
MP_VERBOSE(wl, "Obtained preferred scale, %f, from the compositor.\n",
- wl->scaling);
- wl->pending_vo_events |= VO_EVENT_DPI;
- if (wl->current_output) {
- rescale_geometry(wl, old_scale);
- set_geometry(wl, false);
- prepare_resize(wl, 0, 0);
- }
+ wl->pending_scaling);
+ wl->need_rescale = true;
+
+ // Update scaling now.
+ if (single_output_spanned(wl))
+ update_output_scaling(wl);
}
static const struct wp_fractional_scale_v1_listener fractional_scale_listener = {
@@ -1296,9 +1457,8 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
wl_surface_add_listener(wl->surface, &surface_listener, wl);
}
- if (!strcmp(interface, wl_subcompositor_interface.name) && (ver >= 1) && found++) {
+ if (!strcmp(interface, wl_subcompositor_interface.name) && (ver >= 1) && found++)
wl->subcompositor = wl_registry_bind(reg, id, &wl_subcompositor_interface, 1);
- }
if (!strcmp (interface, zwp_linux_dmabuf_v1_interface.name) && (ver >= 4) && found++) {
wl->dmabuf = wl_registry_bind(reg, id, &zwp_linux_dmabuf_v1_interface, 4);
@@ -1306,13 +1466,11 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
zwp_linux_dmabuf_feedback_v1_add_listener(wl->dmabuf_feedback, &dmabuf_feedback_listener, wl);
}
- if (!strcmp (interface, wp_viewporter_interface.name) && (ver >= 1) && found++) {
- wl->viewporter = wl_registry_bind (reg, id, &wp_viewporter_interface, 1);
- }
+ if (!strcmp (interface, wp_viewporter_interface.name) && (ver >= 1) && found++)
+ wl->viewporter = wl_registry_bind (reg, id, &wp_viewporter_interface, 1);
- if (!strcmp(interface, wl_data_device_manager_interface.name) && (ver >= 3) && found++) {
+ if (!strcmp(interface, wl_data_device_manager_interface.name) && (ver >= 3) && found++)
wl->dnd_devman = wl_registry_bind(reg, id, &wl_data_device_manager_interface, 3);
- }
if (!strcmp(interface, wl_output_interface.name) && (ver >= 2) && found++) {
struct vo_wayland_output *output = talloc_zero(wl, struct vo_wayland_output);
@@ -1329,34 +1487,41 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
}
if (!strcmp(interface, wl_seat_interface.name) && found++) {
- wl->seat = wl_registry_bind(reg, id, &wl_seat_interface, 1);
- wl_seat_add_listener(wl->seat, &seat_listener, wl);
+ if (ver < 5)
+ MP_WARN(wl, "Scrolling won't work because the compositor doesn't "
+ "support version 5 of wl_seat protocol!\n");
+#ifdef HAVE_WAYLAND_1_21
+ ver = MPMIN(ver, 8); /* Cap at 8 in case new events are added later. */
+#else
+ ver = MPMIN(ver, 7);
+#endif
+ struct vo_wayland_seat *seat = talloc_zero(wl, struct vo_wayland_seat);
+ seat->wl = wl;
+ seat->id = id;
+ seat->seat = wl_registry_bind(reg, id, &wl_seat_interface, ver);
+ wl_seat_add_listener(seat->seat, &seat_listener, seat);
+ wl_list_insert(&wl->seat_list, &seat->link);
}
- if (!strcmp(interface, wl_shm_interface.name) && found++) {
+ if (!strcmp(interface, wl_shm_interface.name) && found++)
wl->shm = wl_registry_bind(reg, id, &wl_shm_interface, 1);
- }
#if HAVE_WAYLAND_PROTOCOLS_1_27
- if (!strcmp(interface, wp_content_type_manager_v1_interface.name) && found++) {
+ if (!strcmp(interface, wp_content_type_manager_v1_interface.name) && found++)
wl->content_type_manager = wl_registry_bind(reg, id, &wp_content_type_manager_v1_interface, 1);
- }
- if (!strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) && found++) {
+ if (!strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) && found++)
wl->single_pixel_manager = wl_registry_bind(reg, id, &wp_single_pixel_buffer_manager_v1_interface, 1);
- }
#endif
#if HAVE_WAYLAND_PROTOCOLS_1_31
- if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name) && found++) {
+ if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name) && found++)
wl->fractional_scale_manager = wl_registry_bind(reg, id, &wp_fractional_scale_manager_v1_interface, 1);
- }
#endif
#if HAVE_WAYLAND_PROTOCOLS_1_32
- if (!strcmp(interface, wp_cursor_shape_manager_v1_interface.name) && found++) {
+ if (!strcmp(interface, wp_cursor_shape_manager_v1_interface.name) && found++)
wl->cursor_shape_manager = wl_registry_bind(reg, id, &wp_cursor_shape_manager_v1_interface, 1);
- }
#endif
if (!strcmp(interface, wp_presentation_interface.name) && found++) {
@@ -1370,13 +1535,11 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
xdg_wm_base_add_listener(wl->wm_base, &xdg_wm_base_listener, wl);
}
- if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name) && found++) {
+ if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name) && found++)
wl->xdg_decoration_manager = wl_registry_bind(reg, id, &zxdg_decoration_manager_v1_interface, 1);
- }
- if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) && found++) {
+ if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) && found++)
wl->idle_inhibit_manager = wl_registry_bind(reg, id, &zwp_idle_inhibit_manager_v1_interface, 1);
- }
if (found > 1)
MP_VERBOSE(wl, "Registered for protocol %s\n", interface);
@@ -1385,13 +1548,21 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
static void registry_handle_remove(void *data, struct wl_registry *reg, uint32_t id)
{
struct vo_wayland_state *wl = data;
- struct vo_wayland_output *output, *tmp;
- wl_list_for_each_safe(output, tmp, &wl->output_list, link) {
+ struct vo_wayland_output *output, *output_tmp;
+ wl_list_for_each_safe(output, output_tmp, &wl->output_list, link) {
if (output->id == id) {
remove_output(output);
return;
}
}
+
+ struct vo_wayland_seat *seat, *seat_tmp;
+ wl_list_for_each_safe(seat, seat_tmp, &wl->seat_list, link) {
+ if (seat->id == id) {
+ remove_seat(seat);
+ return;
+ }
+ }
}
static const struct wl_registry_listener registry_listener = {
@@ -1400,6 +1571,26 @@ static const struct wl_registry_listener registry_listener = {
};
/* Static functions */
+static void apply_keepaspect(struct vo_wayland_state *wl, int *width, int *height)
+{
+ if (!wl->vo_opts->keepaspect)
+ return;
+
+ double scale_factor = (double)*width / wl->reduced_width;
+ *width = ceil(wl->reduced_width * scale_factor);
+ if (wl->vo_opts->keepaspect_window)
+ *height = ceil(wl->reduced_height * scale_factor);
+}
+
+static void free_dnd_data(struct vo_wayland_state *wl)
+{
+ // caller should close wl->dnd_fd if appropriate
+
+ wl->dnd_action = -1;
+ TA_FREEP(&wl->dnd_mime_type);
+ wl->dnd_mime_score = 0;
+}
+
static void check_dnd_fd(struct vo_wayland_state *wl)
{
if (wl->dnd_fd == -1)
@@ -1410,40 +1601,44 @@ static void check_dnd_fd(struct vo_wayland_state *wl)
return;
if (fdp.revents & POLLIN) {
- ptrdiff_t offset = 0;
- size_t data_read = 0;
- const size_t chunk_size = 1;
- uint8_t *buffer = ta_zalloc_size(wl, chunk_size);
- if (!buffer)
- goto end;
-
- while ((data_read = read(wl->dnd_fd, buffer + offset, chunk_size)) > 0) {
- offset += data_read;
- buffer = ta_realloc_size(wl, buffer, offset + chunk_size);
- memset(buffer + offset, 0, chunk_size);
- if (!buffer)
- goto end;
+ ssize_t data_read = 0;
+ const size_t chunk_size = 256;
+ bstr file_list = {
+ .start = talloc_zero_size(NULL, chunk_size),
+ };
+
+ while (1) {
+ data_read = read(wl->dnd_fd, file_list.start + file_list.len, chunk_size);
+ if (data_read == -1 && errno == EINTR)
+ continue;
+ else if (data_read <= 0)
+ break;
+ file_list.len += data_read;
+ file_list.start = talloc_realloc_size(NULL, file_list.start, file_list.len + chunk_size);
+ memset(file_list.start + file_list.len, 0, chunk_size);
}
- MP_VERBOSE(wl, "Read %td bytes from the DND fd\n", offset);
+ if (data_read == -1) {
+ MP_VERBOSE(wl, "DND aborted (read error)\n");
+ } else {
+ MP_VERBOSE(wl, "Read %zu bytes from the DND fd\n", file_list.len);
- struct bstr file_list = bstr0(buffer);
- mp_event_drop_mime_data(wl->vo->input_ctx, wl->dnd_mime_type,
- file_list, wl->dnd_action);
- talloc_free(buffer);
-end:
- if (wl->dnd_mime_type)
- talloc_free(wl->dnd_mime_type);
+ if (wl->dnd_offer)
+ wl_data_offer_finish(wl->dnd_offer);
- if (wl->dnd_action >= 0 && wl->dnd_offer)
- wl_data_offer_finish(wl->dnd_offer);
+ assert(wl->dnd_action >= 0);
+ mp_event_drop_mime_data(wl->vo->input_ctx, wl->dnd_mime_type,
+ file_list, wl->dnd_action);
+ }
- wl->dnd_action = -1;
- wl->dnd_mime_type = NULL;
- wl->dnd_mime_score = 0;
+ talloc_free(file_list.start);
+ free_dnd_data(wl);
}
if (fdp.revents & (POLLIN | POLLERR | POLLHUP)) {
+ if (wl->dnd_action >= 0)
+ MP_VERBOSE(wl, "DND aborted (hang up or error)\n");
+ free_dnd_data(wl);
close(wl->dnd_fd);
wl->dnd_fd = -1;
}
@@ -1499,13 +1694,12 @@ static bool create_input(struct vo_wayland_state *wl)
static int create_viewports(struct vo_wayland_state *wl)
{
- if (wl->viewporter) {
- wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface);
- wl->osd_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->osd_surface);
- wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface);
- }
+ wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface);
+ wl->cursor_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->cursor_surface);
+ wl->osd_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->osd_surface);
+ wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface);
- if (wl->viewporter && (!wl->viewport || !wl->osd_viewport || !wl->video_viewport)) {
+ if (!wl->viewport || !wl->osd_viewport || !wl->video_viewport) {
MP_ERR(wl, "failed to create viewport interfaces!\n");
return 1;
}
@@ -1544,8 +1738,6 @@ static void add_feedback(struct vo_wayland_feedback_pool *fback_pool,
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);
}
@@ -1566,7 +1758,7 @@ static char **get_displays_spanned(struct vo_wayland_state *wl)
return names;
}
-static int get_mods(struct vo_wayland_state *wl)
+static int get_mods(struct vo_wayland_seat *s)
{
static char* const mod_names[] = {
XKB_MOD_NAME_SHIFT,
@@ -1585,21 +1777,21 @@ static int get_mods(struct vo_wayland_state *wl)
int modifiers = 0;
for (int n = 0; n < MP_ARRAY_SIZE(mods); n++) {
- xkb_mod_index_t index = xkb_keymap_mod_get_index(wl->xkb_keymap, mod_names[n]);
- if (!xkb_state_mod_index_is_consumed(wl->xkb_state, wl->keyboard_code, index)
- && xkb_state_mod_index_is_active(wl->xkb_state, index,
- XKB_STATE_MODS_DEPRESSED))
+ xkb_mod_index_t index = xkb_keymap_mod_get_index(s->xkb_keymap, mod_names[n]);
+ if (index != XKB_MOD_INVALID
+ && xkb_state_mod_index_is_active(s->xkb_state, index,
+ XKB_STATE_MODS_EFFECTIVE))
modifiers |= mods[n];
}
return modifiers;
}
-static void get_shape_device(struct vo_wayland_state *wl)
+static void get_shape_device(struct vo_wayland_state *wl, struct vo_wayland_seat *s)
{
#if HAVE_WAYLAND_PROTOCOLS_1_32
- if (!wl->cursor_shape_device && wl->cursor_shape_manager) {
- wl->cursor_shape_device = wp_cursor_shape_manager_v1_get_pointer(wl->cursor_shape_manager,
- wl->pointer);
+ if (!s->cursor_shape_device && wl->cursor_shape_manager) {
+ s->cursor_shape_device = wp_cursor_shape_manager_v1_get_pointer(wl->cursor_shape_manager,
+ s->pointer);
}
#endif
}
@@ -1616,8 +1808,17 @@ static void guess_focus(struct vo_wayland_state *wl)
{
// We can't actually know if the window is focused or not in wayland,
// so just guess it with some common sense. Obviously won't work if
- // the user has no keyboard.
- if ((!wl->focused && wl->activated && wl->has_keyboard_input) ||
+ // the user has no keyboard. We flag has_keyboard_input if
+ // at least one seat has it.
+ bool has_keyboard_input = false;
+ struct vo_wayland_seat *seat;
+ wl_list_for_each(seat, &wl->seat_list, link) {
+ if (seat->has_keyboard_input) {
+ has_keyboard_input = true;
+ }
+ }
+
+ if ((!wl->focused && wl->activated && has_keyboard_input) ||
(wl->focused && !wl->activated))
{
wl->focused = !wl->focused;
@@ -1672,12 +1873,10 @@ static int lookupkey(int key)
return mpkey;
}
-static void prepare_resize(struct vo_wayland_state *wl, int width, int height)
+static void prepare_resize(struct vo_wayland_state *wl)
{
- if (!width)
- width = mp_rect_w(wl->geometry) / wl->scaling;
- if (!height)
- height = mp_rect_h(wl->geometry) / wl->scaling;
+ int32_t width = mp_rect_w(wl->geometry) / wl->scaling;
+ int32_t height = mp_rect_h(wl->geometry) / wl->scaling;
xdg_surface_set_window_geometry(wl->xdg_surface, 0, 0, width, height);
wl->pending_vo_events |= VO_EVENT_RESIZE;
}
@@ -1690,6 +1889,9 @@ static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode)
static void rescale_geometry(struct vo_wayland_state *wl, double old_scale)
{
+ if (!wl->vo_opts->hidpi_window_scale && !wl->locked_size)
+ return;
+
double factor = old_scale / wl->scaling;
wl->window_size.x1 /= factor;
wl->window_size.y1 /= factor;
@@ -1734,6 +1936,37 @@ static void remove_output(struct vo_wayland_output *out)
return;
}
+static void remove_seat(struct vo_wayland_seat *seat)
+{
+ if (!seat)
+ return;
+
+ MP_VERBOSE(seat->wl, "Deregistering seat 0x%x\n", seat->id);
+ wl_list_remove(&seat->link);
+ if (seat == seat->wl->last_button_seat)
+ seat->wl->last_button_seat = NULL;
+ if (seat->keyboard)
+ wl_keyboard_destroy(seat->keyboard);
+ if (seat->pointer)
+ wl_pointer_destroy(seat->pointer);
+ if (seat->touch)
+ wl_touch_destroy(seat->touch);
+ if (seat->dnd_ddev)
+ wl_data_device_destroy(seat->dnd_ddev);
+#if HAVE_WAYLAND_PROTOCOLS_1_32
+ if (seat->cursor_shape_device)
+ wp_cursor_shape_device_v1_destroy(seat->cursor_shape_device);
+#endif
+ if (seat->xkb_keymap)
+ xkb_keymap_unref(seat->xkb_keymap);
+ if (seat->xkb_state)
+ xkb_state_unref(seat->xkb_state);
+
+ wl_seat_destroy(seat->seat);
+ talloc_free(seat);
+ return;
+}
+
static void set_content_type(struct vo_wayland_state *wl)
{
if (!wl->content_type_manager)
@@ -1748,20 +1981,23 @@ static void set_content_type(struct vo_wayland_state *wl)
#endif
}
-static void set_cursor_shape(struct vo_wayland_state *wl)
+static void set_cursor_shape(struct vo_wayland_seat *s)
{
#if HAVE_WAYLAND_PROTOCOLS_1_32
- wp_cursor_shape_device_v1_set_shape(wl->cursor_shape_device, wl->pointer_id,
+ wp_cursor_shape_device_v1_set_shape(s->cursor_shape_device, s->pointer_enter_serial,
WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
#endif
}
-static int set_cursor_visibility(struct vo_wayland_state *wl, bool on)
+static int set_cursor_visibility(struct vo_wayland_seat *s, bool on)
{
+ if (!s)
+ return VO_FALSE;
+ struct vo_wayland_state *wl = s->wl;
wl->cursor_visible = on;
if (on) {
- if (wl->cursor_shape_device) {
- set_cursor_shape(wl);
+ if (s->cursor_shape_device) {
+ set_cursor_shape(s);
} else {
if (spawn_cursor(wl))
return VO_FALSE;
@@ -1770,19 +2006,41 @@ static int set_cursor_visibility(struct vo_wayland_state *wl, bool on)
if (!buffer)
return VO_FALSE;
int scale = MPMAX(wl->scaling, 1);
- wl_pointer_set_cursor(wl->pointer, wl->pointer_id, wl->cursor_surface,
+ wl_pointer_set_cursor(s->pointer, s->pointer_enter_serial, wl->cursor_surface,
img->hotspot_x / scale, img->hotspot_y / scale);
- wl_surface_set_buffer_scale(wl->cursor_surface, scale);
+ wp_viewport_set_destination(wl->cursor_viewport, lround(img->width / scale),
+ lround(img->height / scale));
wl_surface_attach(wl->cursor_surface, buffer, 0, 0);
wl_surface_damage_buffer(wl->cursor_surface, 0, 0, img->width, img->height);
}
wl_surface_commit(wl->cursor_surface);
} else {
- wl_pointer_set_cursor(wl->pointer, wl->pointer_id, NULL, 0, 0);
+ wl_pointer_set_cursor(s->pointer, s->pointer_enter_serial, NULL, 0, 0);
}
return VO_TRUE;
}
+static int set_cursor_visibility_all_seats(struct vo_wayland_state *wl, bool on)
+{
+ bool unavailable = true;
+ bool failed = false;
+ struct vo_wayland_seat *seat;
+ wl_list_for_each(seat, &wl->seat_list, link) {
+ if (seat->pointer) {
+ unavailable = false;
+ if (set_cursor_visibility(seat, on) == VO_FALSE)
+ failed = true;
+ }
+ }
+
+ if (unavailable)
+ return VO_NOTAVAIL;
+ if (failed)
+ return VO_FALSE;
+
+ return VO_TRUE;
+}
+
static void set_geometry(struct vo_wayland_state *wl, bool resize)
{
struct vo *vo = wl->vo;
@@ -1805,7 +2063,7 @@ static void set_geometry(struct vo_wayland_state *wl, bool resize)
if (resize) {
if (!wl->locked_size)
wl->geometry = wl->window_size;
- prepare_resize(wl, 0, 0);
+ prepare_resize(wl);
}
}
@@ -1840,15 +2098,16 @@ static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state)
static void set_surface_scaling(struct vo_wayland_state *wl)
{
- if (wl->fractional_scale_manager)
+ if (wl->scale_configured && (wl->fractional_scale_manager ||
+ wl_surface_get_version(wl->surface) >= 6))
+ {
return;
+ }
- // dmabuf_wayland is always wl->scaling = 1
double old_scale = wl->scaling;
- wl->scaling = !wl->using_dmabuf_wayland ? wl->current_output->scale : 1;
-
+ wl->scaling = wl->current_output->scale;
rescale_geometry(wl, old_scale);
- wl_surface_set_buffer_scale(wl->surface, wl->scaling);
+ wl->pending_vo_events |= VO_EVENT_DPI;
}
static void set_window_bounds(struct vo_wayland_state *wl)
@@ -1862,22 +2121,34 @@ static void set_window_bounds(struct vo_wayland_state *wl)
return;
}
+ apply_keepaspect(wl, &wl->bounded_width, &wl->bounded_height);
+
if (wl->bounded_width && wl->bounded_width < wl->window_size.x1)
wl->window_size.x1 = wl->bounded_width;
if (wl->bounded_height && wl->bounded_height < wl->window_size.y1)
wl->window_size.y1 = wl->bounded_height;
}
+static bool single_output_spanned(struct vo_wayland_state *wl)
+{
+ int outputs = 0;
+ struct vo_wayland_output *output;
+ wl_list_for_each(output, &wl->output_list, link) {
+ if (output->has_surface)
+ ++outputs;
+ if (outputs > 1)
+ return false;
+ }
+ return wl->current_output && outputs == 1;
+}
+
static int spawn_cursor(struct vo_wayland_state *wl)
{
- /* Don't use this if we have cursor-shape. */
- if (wl->cursor_shape_device)
- return 0;
- /* Reuse if size is identical */
- if (!wl->pointer || wl->allocated_cursor_scale == wl->scaling)
+ if (wl->allocated_cursor_scale == wl->scaling) {
return 0;
- else if (wl->cursor_theme)
+ } else if (wl->cursor_theme) {
wl_cursor_theme_destroy(wl->cursor_theme);
+ }
const char *xcursor_theme = getenv("XCURSOR_THEME");
const char *size_str = getenv("XCURSOR_SIZE");
@@ -1896,9 +2167,12 @@ static int spawn_cursor(struct vo_wayland_state *wl)
return 1;
}
- wl->default_cursor = wl_cursor_theme_get_cursor(wl->cursor_theme, "left_ptr");
+ wl->default_cursor = wl_cursor_theme_get_cursor(wl->cursor_theme, "default");
+ if (!wl->default_cursor)
+ wl->default_cursor = wl_cursor_theme_get_cursor(wl->cursor_theme, "left_ptr");
+
if (!wl->default_cursor) {
- MP_ERR(wl, "Unable to load cursor theme!\n");
+ MP_ERR(wl, "Unable to get default and left_ptr XCursor from theme!\n");
return 1;
}
@@ -1909,9 +2183,6 @@ static int spawn_cursor(struct vo_wayland_state *wl)
static void toggle_fullscreen(struct vo_wayland_state *wl)
{
- if (!wl->xdg_toplevel)
- return;
- wl->state_change = true;
bool specific_screen = wl->vo_opts->fsscreen_id >= 0 || wl->vo_opts->fsscreen_name;
if (wl->vo_opts->fullscreen && !specific_screen) {
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
@@ -1919,33 +2190,66 @@ static void toggle_fullscreen(struct vo_wayland_state *wl)
struct vo_wayland_output *output = find_output(wl);
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, output->output);
} else {
+ wl->state_change = wl->reconfigured;
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 {
+ wl->state_change = wl->reconfigured;
xdg_toplevel_unset_maximized(wl->xdg_toplevel);
}
}
static void update_app_id(struct vo_wayland_state *wl)
{
- if (!wl->xdg_toplevel)
- return;
xdg_toplevel_set_app_id(wl->xdg_toplevel, wl->vo_opts->appid);
}
+static void update_output_scaling(struct vo_wayland_state *wl)
+{
+ double old_scale = wl->scaling;
+ wl->scaling = wl->pending_scaling;
+ rescale_geometry(wl, old_scale);
+ set_geometry(wl, false);
+ prepare_resize(wl);
+ wl->need_rescale = false;
+ wl->pending_vo_events |= VO_EVENT_DPI;
+}
+
+static void update_output_geometry(struct vo_wayland_state *wl, struct mp_rect old_geometry,
+ struct mp_rect old_output_geometry)
+{
+ if (wl->need_rescale) {
+ update_output_scaling(wl);
+ return;
+ }
+
+ bool force_resize = false;
+ bool use_output_scale = wl_surface_get_version(wl->surface) < 6 &&
+ !wl->fractional_scale_manager &&
+ wl->scaling != wl->current_output->scale;
+
+ if (use_output_scale) {
+ set_surface_scaling(wl);
+ force_resize = true;
+ }
+
+ if (!mp_rect_equals(&old_output_geometry, &wl->current_output->geometry)) {
+ set_geometry(wl, false);
+ force_resize = true;
+ }
+
+ if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize)
+ prepare_resize(wl);
+}
+
static int update_window_title(struct vo_wayland_state *wl, const char *title)
{
- if (!wl->xdg_toplevel)
- return VO_NOTAVAIL;
/* The xdg-shell protocol requires that the title is UTF-8. */
void *tmp = talloc_new(NULL);
struct bstr b_title = bstr_sanitize_utf8_latin1(tmp, bstr0(title));
@@ -1954,12 +2258,6 @@ static int update_window_title(struct vo_wayland_state *wl, const char *title)
return VO_TRUE;
}
-static void window_move(struct vo_wayland_state *wl, uint32_t serial)
-{
- if (wl->xdg_toplevel)
- xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
-}
-
static void wayland_dispatch_events(struct vo_wayland_state *wl, int nfds, int64_t timeout_ns)
{
if (wl->display_fd == -1)
@@ -1994,6 +2292,18 @@ static void wayland_dispatch_events(struct vo_wayland_state *wl, int nfds, int64
wl_display_dispatch_pending(wl->display);
}
+static void begin_dragging(struct vo_wayland_state *wl)
+{
+ struct vo_wayland_seat *s = wl->last_button_seat;
+ if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) &&
+ !wl->locked_size && s)
+ {
+ xdg_toplevel_move(wl->xdg_toplevel, s->seat, s->pointer_button_serial);
+ wl->last_button_seat = NULL;
+ mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
+ }
+}
+
/* Non-static */
int vo_wayland_allocate_memfd(struct vo *vo, size_t size)
{
@@ -2076,8 +2386,6 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
set_input_region(wl, opts->cursor_passthrough);
if (opt == &opts->fullscreen)
toggle_fullscreen(wl);
- if (opt == &opts->hidpi_window_scale)
- set_geometry(wl, true);
if (opt == &opts->window_maximized)
toggle_maximized(wl);
if (opt == &opts->window_minimized)
@@ -2085,6 +2393,7 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
if (opt == &opts->geometry || opt == &opts->autofit ||
opt == &opts->autofit_smaller || opt == &opts->autofit_larger)
{
+ wl->state_change = true;
set_geometry(wl, true);
}
}
@@ -2123,6 +2432,7 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
wl->window_size.x1 = s[0];
wl->window_size.y1 = s[1];
if (!wl->vo_opts->fullscreen && !wl->tiled) {
+ wl->state_change = true;
if (wl->vo_opts->window_maximized) {
xdg_toplevel_unset_maximized(wl->xdg_toplevel);
wl_display_dispatch_pending(wl->display);
@@ -2131,7 +2441,7 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
return VO_TRUE;
}
wl->geometry = wl->window_size;
- prepare_resize(wl, 0, 0);
+ prepare_resize(wl);
}
return VO_TRUE;
}
@@ -2166,12 +2476,13 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
*(double *)arg = wl->scaling;
return VO_TRUE;
}
+ case VOCTRL_BEGIN_DRAGGING:
+ begin_dragging(wl);
+ return VO_TRUE;
case VOCTRL_UPDATE_WINDOW_TITLE:
return update_window_title(wl, (const char *)arg);
case VOCTRL_SET_CURSOR_VISIBILITY:
- if (!wl->pointer)
- return VO_NOTAVAIL;
- return set_cursor_visibility(wl, *(bool *)arg);
+ return set_cursor_visibility_all_seats(wl, *(bool *)arg);
case VOCTRL_KILL_SCREENSAVER:
return set_screensaver_inhibitor(wl, true);
case VOCTRL_RESTORE_SCREENSAVER:
@@ -2181,16 +2492,18 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
return VO_NOTIMPL;
}
-void vo_wayland_handle_fractional_scale(struct vo_wayland_state *wl)
+void vo_wayland_handle_scale(struct vo_wayland_state *wl)
{
- if (wl->fractional_scale_manager && wl->viewport)
- wp_viewport_set_destination(wl->viewport,
- round(mp_rect_w(wl->geometry) / wl->scaling),
- round(mp_rect_h(wl->geometry) / wl->scaling));
+ wp_viewport_set_destination(wl->viewport,
+ lround(mp_rect_w(wl->geometry) / wl->scaling),
+ lround(mp_rect_h(wl->geometry) / wl->scaling));
}
bool vo_wayland_init(struct vo *vo)
{
+ if (!getenv("WAYLAND_DISPLAY"))
+ goto err;
+
vo->wl = talloc_zero(NULL, struct vo_wayland_state);
struct vo_wayland_state *wl = vo->wl;
@@ -2209,9 +2522,10 @@ bool vo_wayland_init(struct vo *vo)
.vo_opts_cache = m_config_cache_alloc(wl, vo->global, &vo_sub_opts),
};
wl->vo_opts = wl->vo_opts_cache->opts;
- wl->using_dmabuf_wayland = !strcmp(wl->vo->driver->name, "dmabuf-wayland");
+ bool using_dmabuf_wayland = !strcmp(wl->vo->driver->name, "dmabuf-wayland");
wl_list_init(&wl->output_list);
+ wl_list_init(&wl->seat_list);
if (!wl->display)
goto err;
@@ -2243,6 +2557,12 @@ bool vo_wayland_init(struct vo *vo)
goto err;
}
+ if (!wl->viewporter) {
+ MP_FATAL(wl, "Compositor doesn't support the required %s protocol!\n",
+ wp_viewporter_interface.name);
+ goto err;
+ }
+
/* Can't be initialized during registry due to multi-protocol dependence */
if (create_viewports(wl))
goto err;
@@ -2279,10 +2599,13 @@ bool vo_wayland_init(struct vo *vo)
}
#endif
- if (wl->dnd_devman && wl->seat) {
- wl->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, wl->seat);
- wl_data_device_add_listener(wl->dnd_ddev, &data_device_listener, wl);
- } else if (!wl->dnd_devman) {
+ if (wl->dnd_devman) {
+ struct vo_wayland_seat *seat;
+ wl_list_for_each(seat, &wl->seat_list, link) {
+ seat->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, seat->seat);
+ wl_data_device_add_listener(seat->dnd_ddev, &data_device_listener, seat);
+ }
+ } else {
MP_VERBOSE(wl, "Compositor doesn't support the %s (ver. 3) protocol!\n",
wl_data_device_manager_interface.name);
}
@@ -2325,7 +2648,7 @@ bool vo_wayland_init(struct vo *vo)
update_app_id(wl);
mp_make_wakeup_pipe(wl->wakeup_pipe);
- wl->callback_surface = wl->using_dmabuf_wayland ? wl->video_surface : wl->surface;
+ wl->callback_surface = using_dmabuf_wayland ? wl->video_surface : wl->surface;
wl->frame_callback = wl_surface_frame(wl->callback_surface);
wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
wl_surface_commit(wl->surface);
@@ -2352,33 +2675,38 @@ bool vo_wayland_reconfig(struct vo *vo)
if (!wl->current_output)
return false;
set_surface_scaling(wl);
+ wl->scale_configured = true;
wl->pending_vo_events |= VO_EVENT_DPI;
}
- if (wl->vo_opts->auto_window_resize || !wl->configured)
+ if (wl->vo_opts->auto_window_resize || !wl->geometry_configured)
set_geometry(wl, false);
+ if (wl->geometry_configured && wl->vo_opts->auto_window_resize)
+ wl->reconfigured = true;
+
if (wl->opts->configure_bounds)
set_window_bounds(wl);
- if (!wl->configured || !wl->locked_size) {
- wl->geometry = wl->window_size;
- wl->configured = true;
- }
-
if (wl->vo_opts->cursor_passthrough)
set_input_region(wl, true);
- if (wl->vo_opts->fullscreen)
- toggle_fullscreen(wl);
+ if (!wl->geometry_configured || !wl->locked_size)
+ wl->geometry = wl->window_size;
- if (wl->vo_opts->window_maximized)
- toggle_maximized(wl);
+ if (!wl->geometry_configured) {
+ if (wl->vo_opts->fullscreen)
+ toggle_fullscreen(wl);
- if (wl->vo_opts->window_minimized)
- do_minimize(wl);
+ if (wl->vo_opts->window_maximized)
+ toggle_maximized(wl);
- prepare_resize(wl, 0, 0);
+ if (wl->vo_opts->window_minimized)
+ do_minimize(wl);
+ wl->geometry_configured = true;
+ }
+
+ prepare_resize(wl);
return true;
}
@@ -2403,6 +2731,10 @@ void vo_wayland_uninit(struct vo *vo)
if (!wl)
return;
+ if (wl->dnd_fd != -1)
+ close(wl->dnd_fd);
+ free_dnd_data(wl);
+
mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
if (wl->compositor)
@@ -2412,9 +2744,6 @@ void vo_wayland_uninit(struct vo *vo)
wl_subcompositor_destroy(wl->subcompositor);
#if HAVE_WAYLAND_PROTOCOLS_1_32
- if (wl->cursor_shape_device)
- wp_cursor_shape_device_v1_destroy(wl->cursor_shape_device);
-
if (wl->cursor_shape_manager)
wp_cursor_shape_manager_v1_destroy(wl->cursor_shape_manager);
#endif
@@ -2433,9 +2762,6 @@ void vo_wayland_uninit(struct vo *vo)
wp_content_type_manager_v1_destroy(wl->content_type_manager);
#endif
- if (wl->dnd_ddev)
- wl_data_device_destroy(wl->dnd_ddev);
-
if (wl->dnd_devman)
wl_data_device_manager_destroy(wl->dnd_devman);
@@ -2462,12 +2788,6 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->idle_inhibit_manager)
zwp_idle_inhibit_manager_v1_destroy(wl->idle_inhibit_manager);
- if (wl->keyboard)
- wl_keyboard_destroy(wl->keyboard);
-
- if (wl->pointer)
- wl_pointer_destroy(wl->pointer);
-
if (wl->presentation)
wp_presentation_destroy(wl->presentation);
@@ -2480,6 +2800,9 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->viewport)
wp_viewport_destroy(wl->viewport);
+ if (wl->cursor_viewport)
+ wp_viewport_destroy(wl->cursor_viewport);
+
if (wl->osd_viewport)
wp_viewport_destroy(wl->osd_viewport);
@@ -2492,9 +2815,6 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->dmabuf_feedback)
zwp_linux_dmabuf_feedback_v1_destroy(wl->dmabuf_feedback);
- if (wl->seat)
- wl_seat_destroy(wl->seat);
-
if (wl->shm)
wl_shm_destroy(wl->shm);
@@ -2536,16 +2856,14 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->xkb_context)
xkb_context_unref(wl->xkb_context);
- if (wl->xkb_keymap)
- xkb_keymap_unref(wl->xkb_keymap);
-
- if (wl->xkb_state)
- xkb_state_unref(wl->xkb_state);
-
- struct vo_wayland_output *output, *tmp;
- wl_list_for_each_safe(output, tmp, &wl->output_list, link)
+ struct vo_wayland_output *output, *output_tmp;
+ wl_list_for_each_safe(output, output_tmp, &wl->output_list, link)
remove_output(output);
+ struct vo_wayland_seat *seat, *seat_tmp;
+ wl_list_for_each_safe(seat, seat_tmp, &wl->seat_list, link)
+ remove_seat(seat);
+
if (wl->display)
wl_display_disconnect(wl->display);