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.c1696
1 files changed, 1139 insertions, 557 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index 04db490c5e..4a86c21c7e 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -29,39 +29,56 @@
#include "input/keycodes.h"
#include "options/m_config.h"
#include "osdep/io.h"
+#include "osdep/poll_wrapper.h"
#include "osdep/timer.h"
#include "present_sync.h"
#include "wayland_common.h"
#include "win_state.h"
// Generated from wayland-protocols
-#include "generated/wayland/idle-inhibit-unstable-v1.h"
-#include "generated/wayland/linux-dmabuf-unstable-v1.h"
-#include "generated/wayland/presentation-time.h"
-#include "generated/wayland/xdg-decoration-unstable-v1.h"
-#include "generated/wayland/xdg-shell.h"
-#include "generated/wayland/viewporter.h"
+#include "idle-inhibit-unstable-v1.h"
+#include "linux-dmabuf-unstable-v1.h"
+#include "presentation-time.h"
+#include "xdg-decoration-unstable-v1.h"
+#include "xdg-shell.h"
+#include "viewporter.h"
#if HAVE_WAYLAND_PROTOCOLS_1_27
-#include "generated/wayland/content-type-v1.h"
-#include "generated/wayland/single-pixel-buffer-v1.h"
+#include "content-type-v1.h"
+#include "single-pixel-buffer-v1.h"
#endif
-#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20
-#define HAVE_WAYLAND_1_20
+#if HAVE_WAYLAND_PROTOCOLS_1_31
+#include "fractional-scale-v1.h"
+#endif
+
+#if HAVE_WAYLAND_PROTOCOLS_1_32
+#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
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW 4
#endif
+#ifndef XDG_TOPLEVEL_STATE_SUSPENDED
+#define XDG_TOPLEVEL_STATE_SUSPENDED 9
+#endif
+
static const struct mp_keymap keymap[] = {
/* Special keys */
- {XKB_KEY_Pause, MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},
- {XKB_KEY_BackSpace, MP_KEY_BS}, {XKB_KEY_Tab, MP_KEY_TAB},
- {XKB_KEY_Return, MP_KEY_ENTER}, {XKB_KEY_Menu, MP_KEY_MENU},
- {XKB_KEY_Print, MP_KEY_PRINT},
+ {XKB_KEY_Pause, MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},
+ {XKB_KEY_BackSpace, MP_KEY_BS}, {XKB_KEY_Tab, MP_KEY_TAB},
+ {XKB_KEY_Return, MP_KEY_ENTER}, {XKB_KEY_Menu, MP_KEY_MENU},
+ {XKB_KEY_Print, MP_KEY_PRINT}, {XKB_KEY_ISO_Left_Tab, MP_KEY_TAB},
/* Cursor keys */
{XKB_KEY_Left, MP_KEY_LEFT}, {XKB_KEY_Right, MP_KEY_RIGHT},
@@ -100,11 +117,11 @@ static const struct mp_keymap keymap[] = {
{XKB_KEY_KP_Decimal, MP_KEY_KPDEC}, {XKB_KEY_KP_Separator, MP_KEY_KPDEC},
/* Numpad without numlock */
- {XKB_KEY_KP_Insert, MP_KEY_KPINS}, {XKB_KEY_KP_End, MP_KEY_KP1},
- {XKB_KEY_KP_Down, MP_KEY_KP2}, {XKB_KEY_KP_Page_Down, MP_KEY_KP3},
- {XKB_KEY_KP_Left, MP_KEY_KP4}, {XKB_KEY_KP_Begin, MP_KEY_KP5},
- {XKB_KEY_KP_Right, MP_KEY_KP6}, {XKB_KEY_KP_Home, MP_KEY_KP7},
- {XKB_KEY_KP_Up, MP_KEY_KP8}, {XKB_KEY_KP_Page_Up, MP_KEY_KP9},
+ {XKB_KEY_KP_Insert, MP_KEY_KPINS}, {XKB_KEY_KP_End, MP_KEY_KPEND},
+ {XKB_KEY_KP_Down, MP_KEY_KPDOWN}, {XKB_KEY_KP_Page_Down, MP_KEY_KPPGDOWN},
+ {XKB_KEY_KP_Left, MP_KEY_KPLEFT}, {XKB_KEY_KP_Begin, MP_KEY_KP5},
+ {XKB_KEY_KP_Right, MP_KEY_KPRIGHT}, {XKB_KEY_KP_Home, MP_KEY_KPHOME},
+ {XKB_KEY_KP_Up, MP_KEY_KPUP}, {XKB_KEY_KP_Page_Up, MP_KEY_KPPGUP},
{XKB_KEY_KP_Delete, MP_KEY_KPDEL},
/* Multimedia keys */
@@ -120,6 +137,9 @@ 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_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}
};
@@ -127,8 +147,9 @@ static const struct mp_keymap keymap[] = {
#define OPT_BASE_STRUCT struct wayland_opts
const struct m_sub_options wayland_conf = {
.opts = (const struct m_option[]) {
- {"wayland-configure-bounds", OPT_FLAG(configure_bounds)},
- {"wayland-disable-vsync", OPT_FLAG(disable_vsync)},
+ {"wayland-configure-bounds", OPT_CHOICE(configure_bounds,
+ {"auto", -1}, {"no", 0}, {"yes", 1})},
+ {"wayland-disable-vsync", OPT_BOOL(disable_vsync)},
{"wayland-edge-pixels-pointer", OPT_INT(edge_pixels_pointer),
M_RANGE(0, INT_MAX)},
{"wayland-edge-pixels-touch", OPT_INT(edge_pixels_touch),
@@ -137,13 +158,18 @@ const struct m_sub_options wayland_conf = {
},
.size = sizeof(struct wayland_opts),
.defaults = &(struct wayland_opts) {
- .configure_bounds = true,
- .disable_vsync = false,
- .edge_pixels_pointer = 10,
+ .configure_bounds = -1,
+ .edge_pixels_pointer = 16,
.edge_pixels_touch = 32,
},
};
+struct vo_wayland_feedback_pool {
+ struct wp_presentation_feedback **fback;
+ struct vo_wayland_state *wl;
+ int len;
+};
+
struct vo_wayland_output {
struct vo_wayland_state *wl;
struct wl_output *output;
@@ -161,50 +187,96 @@ struct vo_wayland_output {
struct wl_list link;
};
-static int check_for_resize(struct vo_wayland_state *wl, wl_fixed_t x_w, wl_fixed_t y_w,
- int edge_pixels, enum xdg_toplevel_resize_edge *edge);
-static int get_mods(struct vo_wayland_state *wl);
+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_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 greatest_common_divisor(struct vo_wayland_state *wl, int a, int b);
+static void add_feedback(struct vo_wayland_feedback_pool *fback_pool,
+ struct wp_presentation_feedback *fback);
+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);
+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 set_geometry(struct vo_wayland_state *wl);
+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;
- wl->mouse_unscaled_x = sx;
- wl->mouse_unscaled_y = sy;
if (!wl->toplevel_configured)
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
@@ -215,9 +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;
- int mpmod = 0;
-
+ 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;
@@ -246,50 +317,107 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
button = 0;
}
- if (wl->keyboard)
- mpmod = get_mods(wl);
-
if (button)
- mp_input_put_key(wl->vo->input_ctx, button | state | 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->vo_opts->fullscreen) && (!wl->vo_opts->window_maximized) &&
- (button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN)) {
- uint32_t edges;
+ !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))
+ {
// Implement an edge resize zone if there are no decorations
- if (!wl->xdg_toplevel_decoration &&
- check_for_resize(wl, wl->mouse_unscaled_x, wl->mouse_unscaled_y,
- wl->opts->edge_pixels_pointer, &edges))
- xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edges);
- else
- window_move(wl, serial);
- // Explictly 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;
+ }
+}
- int mpmod = get_mods(wl);
- double val = wl_fixed_to_double(value) < 0 ? -1 : 1;
+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)
+{
+}
+
+#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 | mpmod, +val);
- if (value < 0)
- mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP | 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 | mpmod, +val);
- if (value < 0)
- mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT | mpmod, -val);
+ s->axis_value120_horizontal += value120;
break;
}
}
+#endif
static const struct wl_pointer_listener pointer_listener = {
pointer_handle_enter,
@@ -297,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, x_w, y_w, 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;
@@ -346,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) {
@@ -371,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;
}
}
@@ -396,37 +554,60 @@ 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;
+ 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);
}
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;
- int mpmod = get_mods(wl);
- int mpkey = lookupkey(sym);
+
if (mpkey) {
- mp_input_put_key(wl->vo->input_ctx, mpkey | state | 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 | 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)
+ s->mpkey = mpkey;
+ if (mpkey && state == MP_KEY_STATE_UP)
+ s->mpkey = 0;
}
static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
@@ -434,18 +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);
+ 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);
}
@@ -462,46 +648,55 @@ 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);
- 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) {
+ if (score > wl->dnd_mime_score && wl->vo_opts->drag_and_drop != -2) {
wl->dnd_mime_score = score;
- talloc_free(wl->dnd_mime_type);
+ if (wl->dnd_mime_type)
+ talloc_free(wl->dnd_mime_type);
wl->dnd_mime_type = talloc_strdup(wl, mime_type);
MP_VERBOSE(wl, "Given DND offer with mime type %s\n", wl->dnd_mime_type);
}
@@ -513,11 +708,24 @@ 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;
- 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");
+ 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;
+ } else {
+ wl->dnd_action = dnd_action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ?
+ 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]);
+ }
}
static const struct wl_data_offer_listener data_offer_listener = {
@@ -529,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,
@@ -542,24 +751,27 @@ 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;
}
- wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
- WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
- WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
-
- wl_data_offer_accept(id, serial, wl->dnd_mime_type);
+ if (wl->vo_opts->drag_and_drop != -2) {
+ wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
+ wl_data_offer_accept(id, serial, wl->dnd_mime_type);
+ MP_VERBOSE(wl, "Accepting DND offer with mime type %s\n", wl->dnd_mime_type);
+ }
- MP_VERBOSE(wl, "Accepting DND offer with mime type %s\n", wl->dnd_mime_type);
}
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)
@@ -568,24 +780,26 @@ static void data_device_handle_leave(void *data, struct wl_data_device *wl_ddev)
wl->dnd_offer = NULL;
}
- MP_VERBOSE(wl, "Releasing DND offer with mime type %s\n", wl->dnd_mime_type);
-
- talloc_free(wl->dnd_mime_type);
- wl->dnd_mime_type = NULL;
- wl->dnd_mime_score = 0;
+ if (wl->vo_opts->drag_and_drop != -2) {
+ MP_VERBOSE(wl, "Releasing DND offer with mime type %s\n", wl->dnd_mime_type);
+ if (wl->dnd_mime_type)
+ TA_FREEP(&wl->dnd_mime_type);
+ wl->dnd_mime_score = 0;
+ }
}
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];
@@ -594,18 +808,20 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_ddev)
return;
}
- MP_VERBOSE(wl, "Receiving DND offer with mime %s\n", wl->dnd_mime_type);
+ if (wl->vo_opts->drag_and_drop != -2) {
+ MP_VERBOSE(wl, "Receiving DND offer with mime %s\n", wl->dnd_mime_type);
+ wl_data_offer_receive(wl->dnd_offer, wl->dnd_mime_type, pipefd[1]);
+ }
- wl_data_offer_receive(wl->dnd_offer, wl->dnd_mime_type, pipefd[1]);
close(pipefd[1]);
-
wl->dnd_fd = pipefd[0];
}
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);
@@ -676,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);
- wl->pending_vo_events |= VO_EVENT_DPI;
- wl->pending_vo_events |= VO_EVENT_RESIZE;
+ set_geometry(wl, false);
+ prepare_resize(wl);
}
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
@@ -696,7 +910,6 @@ static void output_handle_scale(void *data, struct wl_output *wl_output,
output->scale = factor;
}
-#ifdef HAVE_WAYLAND_1_20
static void output_handle_name(void *data, struct wl_output *wl_output,
const char *name)
{
@@ -708,17 +921,14 @@ static void output_handle_description(void *data, struct wl_output *wl_output,
const char *description)
{
}
-#endif
static const struct wl_output_listener output_listener = {
output_handle_geometry,
output_handle_mode,
output_handle_done,
output_handle_scale,
-#ifdef HAVE_WAYLAND_1_20
output_handle_name,
output_handle_description,
-#endif
};
static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
@@ -732,34 +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 (outputs == 1)
+ update_output_geometry(wl, old_geometry, old_output_geometry);
- if (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);