diff options
author | Rostislav Pehlivanov <atomnuker@gmail.com> | 2017-10-01 21:16:49 +0100 |
---|---|---|
committer | Rostislav Pehlivanov <atomnuker@gmail.com> | 2017-10-03 19:36:02 +0100 |
commit | 68f9ee7e0b3fdddfa42fa11a15d9ae84460d5e19 (patch) | |
tree | 91b3c4dd976c54a241dc17d04ccdd15e1cf70ff8 /video/out/wayland_common.c | |
parent | 980116360b0f393e16064ec3b7a4ef9efb14372e (diff) | |
download | mpv-68f9ee7e0b3fdddfa42fa11a15d9ae84460d5e19.tar.bz2 mpv-68f9ee7e0b3fdddfa42fa11a15d9ae84460d5e19.tar.xz |
wayland_common: rewrite from scratch
The wayland code was written more than 4 years ago when wayland wasn't
even at version 1.0. This commit rewrites everything in a more modern way,
switches to using the new xdg v6 shell interface which solves a lot of bugs
and makes mpv tiling-friedly, adds support for drag and drop, adds support
for touchscreens, adds support for KDE's server decorations protocol,
and finally adds support for the new idle-inhibitor protocol.
It does not yet use the frame callback as a main rendering loop driver,
this will happen with a later commit.
Diffstat (limited to 'video/out/wayland_common.c')
-rw-r--r-- | video/out/wayland_common.c | 1720 |
1 files changed, 927 insertions, 793 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index fedebb3f8d..fb98308de2 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -1,8 +1,5 @@ /* * This file is part of mpv video player. - * Copyright © 2008 Kristian Høgsberg - * Copyright © 2012-2013 Collabora, Ltd. - * Copyright © 2013 Alexander Preisinger <alexander.preisinger@gmail.com> * * mpv is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,80 +15,269 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <inttypes.h> -#include <limits.h> -#include <assert.h> #include <poll.h> #include <unistd.h> - -#include <sys/mman.h> #include <linux/input.h> - -#include "config.h" -#include "misc/bstr.h" -#include "options/options.h" #include "common/msg.h" -#include "mpv_talloc.h" - -#include "wayland_common.h" - -#include "vo.h" -#include "win_state.h" +#include "input/input.h" +#include "input/keycodes.h" #include "osdep/io.h" #include "osdep/timer.h" +#include "win_state.h" +#include "wayland_common.h" -#include "input/input.h" -#include "input/event.h" -#include "input/keycodes.h" +// Generated from xdg-shell-unstable-v6.xml +#include "video/out/wayland/xdg-shell-v6.h" -static int lookupkey(int key); +// Generated from idle-inhibit-unstable-v1.xml +#include "video/out/wayland/idle-inhibit-v1.h" -static void hide_cursor(struct vo_wayland_state * wl); -static void show_cursor(struct vo_wayland_state * wl); -static void window_move(struct vo_wayland_state * wl, uint32_t serial); -static void window_set_title(struct vo_wayland_state * wl, const char *title); -static void schedule_resize(struct vo_wayland_state *wl, - uint32_t edges, - int32_t width, - int32_t height); +// Generated from server-decoration.xml +#include "video/out/wayland/srv-decor.h" -static void vo_wayland_fullscreen(struct vo *vo); +static void xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial) +{ + zxdg_shell_v6_pong(shell, serial); +} -static const struct wl_callback_listener frame_listener; +static const struct zxdg_shell_v6_listener xdg_shell_listener = { + xdg_shell_ping, +}; + +static void set_cursor_visibility(struct vo_wayland_state *wl, int on) +{ + if (!wl->pointer) + return; + if (on) { + struct wl_cursor_image *image = wl->default_cursor->images[0]; + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + if (!buffer) + return; + wl_pointer_set_cursor(wl->pointer, wl->pointer_id, wl->cursor_surface, + image->hotspot_x, image->hotspot_y); + wl_surface_attach(wl->cursor_surface, buffer, 0, 0); + wl_surface_damage(wl->cursor_surface, 0, 0, image->width, image->height); + wl_surface_commit(wl->cursor_surface); + } else { + wl_pointer_set_cursor(wl->pointer, wl->pointer_id, NULL, 0, 0); + } +} + +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; + + set_cursor_visibility(wl, 1); + mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_ENTER); +} + +static void pointer_handle_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) +{ + struct vo_wayland_state *wl = data; + 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; + + wl->mouse_x = wl_fixed_to_int(sx) * wl->scaling; + wl->mouse_y = wl_fixed_to_int(sy) * wl->scaling; + + mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y); +} + +static void window_move(struct vo_wayland_state *wl, uint32_t serial) +{ + if (wl->xdg_toplevel) + zxdg_toplevel_v6_move(wl->xdg_toplevel, wl->seat, serial); +} + +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; + + state = state == WL_POINTER_BUTTON_STATE_PRESSED ? MP_KEY_STATE_DOWN + : MP_KEY_STATE_UP; + + button = button == BTN_LEFT ? MP_MBTN_LEFT : + button == BTN_MIDDLE ? MP_MBTN_MID : MP_MBTN_RIGHT; + + mp_input_put_key(wl->vo->input_ctx, button | state); + + if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) && + (button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN)) + window_move(wl, serial); +} + +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; + double val = wl_fixed_to_double(value)*0.1; + switch (axis) { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + if (value > 0) + mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_DOWN, +val); + if (value < 0) + mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP, -val); + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + if (value > 0) + mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_RIGHT, +val); + if (value < 0) + mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT, -val); + break; + } +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, +}; + +static int check_for_resize(struct vo_wayland_state *wl, wl_fixed_t x_w, wl_fixed_t y_w, + enum zxdg_toplevel_v6_resize_edge *edge) +{ + if (wl->touch_entries || wl->fullscreen) + return 0; + + const int edge_pixels = 64; + int pos[2] = { wl_fixed_to_double(x_w), wl_fixed_to_double(y_w) }; + int left_edge = pos[0] < edge_pixels; + int top_edge = pos[1] < edge_pixels; + int right_edge = pos[0] > (mp_rect_w(wl->geometry) - edge_pixels); + int bottom_edge = pos[1] > (mp_rect_h(wl->geometry) - edge_pixels); + + if (left_edge) { + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT; + if (top_edge) + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT; + else if (bottom_edge) + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT; + } else if (right_edge) { + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT; + if (top_edge) + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT; + else if (bottom_edge) + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT; + } else if (top_edge) { + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP; + } else if (bottom_edge) { + *edge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM; + } else { + *edge = 0; + return 0; + } + + return 1; +} + +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; + + enum zxdg_toplevel_v6_resize_edge edge; + if (check_for_resize(wl, x_w, y_w, &edge)) { + wl->touch_entries = 0; + zxdg_toplevel_v6_resize(wl->xdg_toplevel, wl->seat, serial, edge); + return; + } else if (wl->touch_entries) { + wl->touch_entries = 0; + zxdg_toplevel_v6_move(wl->xdg_toplevel, wl->seat, serial); + return; + } + + wl->touch_entries = 1; + + wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling; + wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling; + + 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); +} + +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; + + wl->touch_entries = 0; + + mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP); +} + +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; + + wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling; + wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling; + + mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y); +} + +static void touch_handle_frame(void *data, struct wl_touch *wl_touch) +{ +} + +static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) +{ +} + +static const struct wl_touch_listener touch_listener = { + touch_handle_down, + touch_handle_up, + touch_handle_motion, + touch_handle_frame, + touch_handle_cancel, +}; static const struct mp_keymap keymap[] = { - // special keys + /* 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}, - // cursor keys + /* Cursor keys */ {XKB_KEY_Left, MP_KEY_LEFT}, {XKB_KEY_Right, MP_KEY_RIGHT}, {XKB_KEY_Up, MP_KEY_UP}, {XKB_KEY_Down, MP_KEY_DOWN}, - // navigation block + /* Navigation keys */ {XKB_KEY_Insert, MP_KEY_INSERT}, {XKB_KEY_Delete, MP_KEY_DELETE}, {XKB_KEY_Home, MP_KEY_HOME}, {XKB_KEY_End, MP_KEY_END}, {XKB_KEY_Page_Up, MP_KEY_PAGE_UP}, {XKB_KEY_Page_Down, MP_KEY_PAGE_DOWN}, - // F-keys - {XKB_KEY_F1, MP_KEY_F+1}, {XKB_KEY_F2, MP_KEY_F+2}, - {XKB_KEY_F3, MP_KEY_F+3}, {XKB_KEY_F4, MP_KEY_F+4}, - {XKB_KEY_F5, MP_KEY_F+5}, {XKB_KEY_F6, MP_KEY_F+6}, - {XKB_KEY_F7, MP_KEY_F+7}, {XKB_KEY_F8, MP_KEY_F+8}, - {XKB_KEY_F9, MP_KEY_F+9}, {XKB_KEY_F10, MP_KEY_F+10}, - {XKB_KEY_F11, MP_KEY_F+11}, {XKB_KEY_F12, MP_KEY_F+12}, + /* F-keys */ + {XKB_KEY_F1, MP_KEY_F + 1}, {XKB_KEY_F2, MP_KEY_F + 2}, + {XKB_KEY_F3, MP_KEY_F + 3}, {XKB_KEY_F4, MP_KEY_F + 4}, + {XKB_KEY_F5, MP_KEY_F + 5}, {XKB_KEY_F6, MP_KEY_F + 6}, + {XKB_KEY_F7, MP_KEY_F + 7}, {XKB_KEY_F8, MP_KEY_F + 8}, + {XKB_KEY_F9, MP_KEY_F + 9}, {XKB_KEY_F10, MP_KEY_F +10}, + {XKB_KEY_F11, MP_KEY_F +11}, {XKB_KEY_F12, MP_KEY_F +12}, - // numpad independent of numlock - {XKB_KEY_KP_Subtract, '-'}, {XKB_KEY_KP_Add, '+'}, + /* Numpad independent of numlock */ + {XKB_KEY_KP_Subtract, '-'}, {XKB_KEY_KP_Add, '+'}, {XKB_KEY_KP_Multiply, '*'}, {XKB_KEY_KP_Divide, '/'}, {XKB_KEY_KP_Enter, MP_KEY_KPENTER}, - // numpad with numlock + /* Numpad with numlock */ {XKB_KEY_KP_0, MP_KEY_KP0}, {XKB_KEY_KP_1, MP_KEY_KP1}, {XKB_KEY_KP_2, MP_KEY_KP2}, {XKB_KEY_KP_3, MP_KEY_KP3}, {XKB_KEY_KP_4, MP_KEY_KP4}, {XKB_KEY_KP_5, MP_KEY_KP5}, @@ -99,7 +285,7 @@ static const struct mp_keymap keymap[] = { {XKB_KEY_KP_8, MP_KEY_KP8}, {XKB_KEY_KP_9, MP_KEY_KP9}, {XKB_KEY_KP_Decimal, MP_KEY_KPDEC}, {XKB_KEY_KP_Separator, MP_KEY_KPDEC}, - // numpad without numlock + /* 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}, @@ -107,7 +293,7 @@ static const struct mp_keymap keymap[] = { {XKB_KEY_KP_Up, MP_KEY_KP8}, {XKB_KEY_KP_Page_Up, MP_KEY_KP9}, {XKB_KEY_KP_Delete, MP_KEY_KPDEL}, - // "Multimedia keyboard" keys + /* Multimedia keys */ {XKB_KEY_XF86MenuKB, MP_KEY_MENU}, {XKB_KEY_XF86AudioPlay, MP_KEY_PLAY}, {XKB_KEY_XF86AudioPause, MP_KEY_PAUSE}, {XKB_KEY_XF86AudioStop, MP_KEY_STOP}, @@ -124,137 +310,8 @@ static const struct mp_keymap keymap[] = { {0, 0} }; - -/** Wayland listeners **/ - -static void ssurface_handle_ping(void *data, - struct wl_shell_surface *shell_surface, - uint32_t serial) -{ - wl_shell_surface_pong(shell_surface, serial); -} - -static void ssurface_handle_configure(void *data, - struct wl_shell_surface *shell_surface, - uint32_t edges, - int32_t width, - int32_t height) -{ - struct vo_wayland_state *wl = data; - float win_aspect = wl->window.aspect; - if (!width || !height) - return; - if (!wl->window.is_fullscreen) - width = win_aspect * height; - schedule_resize(wl, edges, width, height); -} - -static void ssurface_handle_popup_done(void *data, - struct wl_shell_surface *shell_surface) -{ -} - -static const struct wl_shell_surface_listener shell_surface_listener = { - ssurface_handle_ping, - ssurface_handle_configure, - ssurface_handle_popup_done -}; - -static void output_handle_geometry(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform) -{ - struct vo_wayland_output *output = data; - output->make = make; - output->model = model; -} - -static void output_handle_mode(void *data, - struct wl_output *wl_output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) -{ - struct vo_wayland_output *output = data; - - // only save current mode - if (!output || !(flags & WL_OUTPUT_MODE_CURRENT)) - return; - - output->width = width; - output->height = height; - output->flags = flags; - output->refresh_rate = refresh; -} - -static void output_handle_done(void* data, struct wl_output *wl_output) -{ -} - -static void output_handle_scale(void* data, struct wl_output *wl_output, - int32_t factor) -{ - struct vo_wayland_output *output = data; - output->scale = factor; -} - -static const struct wl_output_listener output_listener = { - output_handle_geometry, - output_handle_mode, - output_handle_done, - output_handle_scale -}; - - -/* SURFACE LISTENER */ - -static void surface_handle_enter(void *data, - struct wl_surface *wl_surface, - struct wl_output *output) -{ - struct vo_wayland_state *wl = data; - wl->display.current_output = NULL; - - struct vo_wayland_output *o; - wl_list_for_each(o, &wl->display.output_list, link) { - if (o->output == output) { - wl->display.current_output = o; - break; - } - } - - wl->window.events |= VO_EVENT_WIN_STATE | VO_EVENT_RESIZE; -} - -static void surface_handle_leave(void *data, - struct wl_surface *wl_surface, - struct wl_output *output) -{ - // window can be displayed at 2 output, but we only use the most recently - // entered and discard the previous one even if a part of the window is - // still visible on the previous entered output. - // Don't bother with a "leave" logic -} - -static const struct wl_surface_listener surface_listener = { - surface_handle_enter, - surface_handle_leave -}; - -/* KEYBOARD LISTENER */ -static void keyboard_handle_keymap(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t format, - int32_t fd, - uint32_t size) +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; char *map_str; @@ -270,68 +327,97 @@ static void keyboard_handle_keymap(void *data, return; } - wl->input.xkb.keymap = xkb_keymap_new_from_string(wl->input.xkb.context, - map_str, - XKB_KEYMAP_FORMAT_TEXT_V1, - 0); + wl->xkb_keymap = xkb_keymap_new_from_string(wl->xkb_context, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(map_str, size); close(fd); - if (!wl->input.xkb.keymap) { + if (!wl->xkb_keymap) { MP_ERR(wl, "failed to compile keymap\n"); return; } - wl->input.xkb.state = xkb_state_new(wl->input.xkb.keymap); - if (!wl->input.xkb.state) { + wl->xkb_state = xkb_state_new(wl->xkb_keymap); + if (!wl->xkb_state) { MP_ERR(wl, "failed to create XKB state\n"); - xkb_keymap_unref(wl->input.xkb.keymap); - wl->input.xkb.keymap = NULL; + xkb_keymap_unref(wl->xkb_keymap); + wl->xkb_keymap = NULL; return; } } -static void keyboard_handle_enter(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - struct wl_surface *surface, +static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { } -static void keyboard_handle_leave(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - struct wl_surface *surface) +static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) { } -static void keyboard_handle_key(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - uint32_t time, - uint32_t key, +static bool create_input(struct vo_wayland_state *wl) +{ + wl->xkb_context = xkb_context_new(0); + + if (!wl->xkb_context) { + MP_ERR(wl, "failed to initialize input: check xkbcommon\n"); + return 1; + } + + return 0; +} + +static int lookupkey(int key) +{ + const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]"; + + int mpkey = 0; + if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') || + (key >= '0' && key <= '9') || + (key > 0 && key < 256 && strchr(passthrough_keys, key))) + mpkey = key; + + if (!mpkey) + mpkey = lookup_keymap_table(keymap, key); + + return mpkey; +} + +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; uint32_t code = code = key + 8; - xkb_keysym_t sym = xkb_state_key_get_one_sym(wl->input.xkb.state, code); + xkb_keysym_t sym = xkb_state_key_get_one_sym(wl->xkb_state, code); int mpmod = state == WL_KEYBOARD_KEY_STATE_PRESSED ? MP_KEY_STATE_DOWN : MP_KEY_STATE_UP; - static const char *mod_names[] = {XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CTRL, - XKB_MOD_NAME_ALT, XKB_MOD_NAME_LOGO, 0}; - static int mods[] = {MP_KEY_MODIFIER_SHIFT, MP_KEY_MODIFIER_CTRL, - MP_KEY_MODIFIER_ALT, MP_KEY_MODIFIER_META, 0}; + static const char *mod_names[] = { + XKB_MOD_NAME_SHIFT, + XKB_MOD_NAME_CTRL, + XKB_MOD_NAME_ALT, + XKB_MOD_NAME_LOGO, + 0, + }; + + static int mods[] = { + MP_KEY_MODIFIER_SHIFT, + MP_KEY_MODIFIER_CTRL, + MP_KEY_MODIFIER_ALT, + MP_KEY_MODIFIER_META, + 0, + }; for (int n = 0; mods[n]; n++) { - xkb_mod_index_t index = - xkb_keymap_mod_get_index(wl->input.xkb.keymap, mod_names[n]); - if (!xkb_state_mod_index_is_consumed(wl->input.xkb.state, code, index) - && xkb_state_mod_index_is_active(wl->input.xkb.state, index, + 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, code, index) + && xkb_state_mod_index_is_active(wl->xkb_state, index, XKB_STATE_MODS_DEPRESSED)) mpmod |= mods[n]; } @@ -340,42 +426,29 @@ static void keyboard_handle_key(void *data, if (mpkey) { mp_input_put_key(wl->vo->input_ctx, mpkey | mpmod); } else { - char s[80]; + char s[128]; if (xkb_keysym_to_utf8(sym, s, sizeof(s)) > 0) mp_input_put_key_utf8(wl->vo->input_ctx, mpmod, bstr0(s)); } } -static void keyboard_handle_modifiers(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - uint32_t mods_depressed, - uint32_t mods_latched, - uint32_t mods_locked, +static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct vo_wayland_state *wl = data; - xkb_state_update_mask(wl->input.xkb.state, - mods_depressed, - mods_latched, - mods_locked, - 0, 0, group); + xkb_state_update_mask(wl->xkb_state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); } -static void keyboard_handle_repeat_info(void *data, - struct wl_keyboard *wl_keyboard, - int32_t rate, - int32_t delay) +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; - if (wl->vo->opts->native_keyrepeat) { - if (rate < 0 || delay < 0) { - MP_WARN(wl, "Invalid rate or delay values sent by compositor\n"); - return; - } + if (wl->vo->opts->native_keyrepeat) mp_input_set_repeat_info(wl->vo->input_ctx, rate, delay); - } } static const struct wl_keyboard_listener keyboard_listener = { @@ -384,786 +457,847 @@ static const struct wl_keyboard_listener keyboard_listener = { keyboard_handle_leave, keyboard_handle_key, keyboard_handle_modifiers, - keyboard_handle_repeat_info + keyboard_handle_repeat_info, }; -/* POINTER LISTENER */ -static void pointer_handle_enter(void *data, - struct wl_pointer *pointer, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t sx_w, - wl_fixed_t sy_w) +static void seat_handle_caps(void *data, struct wl_seat *seat, + enum wl_seat_capability caps) { struct vo_wayland_state *wl = data; - wl->cursor.serial = serial; - wl->cursor.pointer = pointer; + 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; + } - /* Release the left button on pointer enter again - * because after moving the shell surface no release event is sent */ - mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_ENTER); - mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP); - show_cursor(wl); + 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_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; + } } -static void pointer_handle_leave(void *data, - struct wl_pointer *pointer, - uint32_t serial, - struct wl_surface *surface) +static const struct wl_seat_listener seat_listener = { + seat_handle_caps, +}; + +static void output_handle_geometry(void *data, struct wl_output *wl_output, + int32_t x, int32_t y, int32_t phys_width, + int32_t phys_height, int32_t subpixel, + const char *make, const char *model, + int32_t transform) { - struct vo_wayland_state *wl = data; - mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_LEAVE); + struct vo_wayland_output *output = data; + output->make = make; + output->model = model; + output->geometry.x0 = x; + output->geometry.y0 = y; } -static void pointer_handle_motion(void *data, - struct wl_pointer *pointer, - uint32_t time, - wl_fixed_t sx_w, - wl_fixed_t sy_w) +static void output_handle_mode(void *data, struct wl_output *wl_output, + uint32_t flags, int32_t width, + int32_t height, int32_t refresh) { - int32_t scale = 1; - struct vo_wayland_state *wl = data; + struct vo_wayland_output *output = data; - if (wl->display.current_output) - scale = wl->display.current_output->scale; + /* Only save current mode */ + if (!output || !(flags & WL_OUTPUT_MODE_CURRENT)) + return; - wl->cursor.pointer = pointer; - wl->window.mouse_x = scale*wl_fixed_to_int(sx_w); - wl->window.mouse_y = scale*wl_fixed_to_int(sy_w); + output->width = width; + output->height = height; + output->geometry.x1 = width + output->geometry.x0; + output->geometry.y1 = height + output->geometry.y0; + output->flags = flags; + output->refresh_rate = (double)refresh * 0.001; +} - mp_input_set_mouse_pos(wl->vo->input_ctx, wl->window.mouse_x, - wl->window.mouse_y); +static void output_handle_done(void* data, struct wl_output *wl_output) +{ } -static void pointer_handle_button(void *data, - struct wl_pointer *pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) +static void output_handle_scale(void* data, struct wl_output *wl_output, + int32_t factor) { - struct vo_wayland_state *wl = data; + struct vo_wayland_output *output = data; + output->scale = factor; +} - state = state == WL_POINTER_BUTTON_STATE_PRESSED ? MP_KEY_STATE_DOWN - : MP_KEY_STATE_UP; +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, + output_handle_done, + output_handle_scale, +}; - button = button == BTN_LEFT ? MP_MBTN_LEFT : - button == BTN_MIDDLE ? MP_MBTN_MID : MP_MBTN_RIGHT; +static void data_offer_handle_offer(void *data, struct wl_data_offer *offer, + const char *mime_type) +{ + struct vo_wayland_state *wl = data; + int score = mp_event_get_mime_type_score(wl->vo->input_ctx, mime_type); + if (score > wl->dnd_mime_score) { + wl->dnd_mime_score = score; + 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); + } +} - mp_input_put_key(wl->vo->input_ctx, button | state); +static void data_offer_source_actions(void *data, struct wl_data_offer *offer, uint32_t source_actions) +{ - if (!mp_input_test_dragging(wl->vo->input_ctx, wl->window.mouse_x, wl->window.mouse_y) && - (button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN)) - window_move(wl, serial); } -static void pointer_handle_axis(void *data, - struct wl_pointer *pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) +static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action) { struct vo_wayland_state *wl = data; - - // value is 10.00 on a normal mouse wheel - // scale it down to 1.00 for multipliying it with the commands - if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - if (value > 0) - mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_DOWN, - wl_fixed_to_double(value)*0.1); - if (value < 0) - mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP, - wl_fixed_to_double(value)*-0.1); - } - else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - if (value > 0) - mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_RIGHT, - wl_fixed_to_double(value)*0.1); - if (value < 0) - mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT, - wl_fixed_to_double(value)*-0.1); - } + 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 struct wl_pointer_listener pointer_listener = { - pointer_handle_enter, - pointer_handle_leave, - pointer_handle_motion, - pointer_handle_button, - pointer_handle_axis, +static const struct wl_data_offer_listener data_offer_listener = { + data_offer_handle_offer, + data_offer_source_actions, + data_offer_action, }; -static void seat_handle_capabilities(void *data, - struct wl_seat *seat, - enum wl_seat_capability caps) +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; + if (wl->dnd_offer) + wl_data_offer_destroy(wl->dnd_offer); - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl->input.keyboard) { - wl->input.keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(wl->input.keyboard, &keyboard_listener, wl); - } - else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl->input.keyboard) { - wl_keyboard_destroy(wl->input.keyboard); - wl->input.keyboard = NULL; - } - if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl->input.pointer) { - wl->input.pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(wl->input.pointer, &pointer_listener, wl); - } - else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->input.pointer) { - wl_pointer_destroy(wl->input.pointer); - wl->input.pointer = NULL; + wl->dnd_offer = id; + wl_data_offer_add_listener(id, &data_offer_listener, wl); +} + +static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t x, wl_fixed_t y, + struct wl_data_offer *id) +{ + struct vo_wayland_state *wl = data; + 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); + + MP_VERBOSE(wl, "Accepting DND offer with mime type %s\n", wl->dnd_mime_type); } -static void seat_handle_name(void *data, - |