1 /*
2  * This file is part of mpv video player.
3  *
4  * mpv is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * mpv is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <errno.h>
19 #include <limits.h>
20 #include <linux/input-event-codes.h>
21 #include <poll.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <wayland-cursor.h>
25 #include <xkbcommon/xkbcommon.h>
26 
27 #include "common/msg.h"
28 #include "input/input.h"
29 #include "input/keycodes.h"
30 #include "options/m_config.h"
31 #include "osdep/io.h"
32 #include "osdep/timer.h"
33 #include "wayland_common.h"
34 #include "win_state.h"
35 
36 // Generated from wayland-protocols
37 #include "generated/wayland/idle-inhibit-unstable-v1.h"
38 #include "generated/wayland/presentation-time.h"
39 #include "generated/wayland/xdg-decoration-unstable-v1.h"
40 #include "generated/wayland/xdg-shell.h"
41 
42 static const struct mp_keymap keymap[] = {
43     /* Special keys */
44     {XKB_KEY_Pause,     MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},
45     {XKB_KEY_BackSpace, MP_KEY_BS},    {XKB_KEY_Tab,    MP_KEY_TAB},
46     {XKB_KEY_Return,    MP_KEY_ENTER}, {XKB_KEY_Menu,   MP_KEY_MENU},
47     {XKB_KEY_Print,     MP_KEY_PRINT},
48 
49     /* Cursor keys */
50     {XKB_KEY_Left, MP_KEY_LEFT}, {XKB_KEY_Right, MP_KEY_RIGHT},
51     {XKB_KEY_Up,   MP_KEY_UP},   {XKB_KEY_Down,  MP_KEY_DOWN},
52 
53     /* Navigation keys */
54     {XKB_KEY_Insert,  MP_KEY_INSERT},  {XKB_KEY_Delete,    MP_KEY_DELETE},
55     {XKB_KEY_Home,    MP_KEY_HOME},    {XKB_KEY_End,       MP_KEY_END},
56     {XKB_KEY_Page_Up, MP_KEY_PAGE_UP}, {XKB_KEY_Page_Down, MP_KEY_PAGE_DOWN},
57 
58     /* F-keys */
59     {XKB_KEY_F1,  MP_KEY_F + 1},  {XKB_KEY_F2,  MP_KEY_F + 2},
60     {XKB_KEY_F3,  MP_KEY_F + 3},  {XKB_KEY_F4,  MP_KEY_F + 4},
61     {XKB_KEY_F5,  MP_KEY_F + 5},  {XKB_KEY_F6,  MP_KEY_F + 6},
62     {XKB_KEY_F7,  MP_KEY_F + 7},  {XKB_KEY_F8,  MP_KEY_F + 8},
63     {XKB_KEY_F9,  MP_KEY_F + 9},  {XKB_KEY_F10, MP_KEY_F +10},
64     {XKB_KEY_F11, MP_KEY_F +11},  {XKB_KEY_F12, MP_KEY_F +12},
65 
66     /* Numpad independent of numlock */
67     {XKB_KEY_KP_Subtract, '-'}, {XKB_KEY_KP_Add,    '+'},
68     {XKB_KEY_KP_Multiply, '*'}, {XKB_KEY_KP_Divide, '/'},
69     {XKB_KEY_KP_Enter, MP_KEY_KPENTER},
70 
71     /* Numpad with numlock */
72     {XKB_KEY_KP_0, MP_KEY_KP0}, {XKB_KEY_KP_1, MP_KEY_KP1},
73     {XKB_KEY_KP_2, MP_KEY_KP2}, {XKB_KEY_KP_3, MP_KEY_KP3},
74     {XKB_KEY_KP_4, MP_KEY_KP4}, {XKB_KEY_KP_5, MP_KEY_KP5},
75     {XKB_KEY_KP_6, MP_KEY_KP6}, {XKB_KEY_KP_7, MP_KEY_KP7},
76     {XKB_KEY_KP_8, MP_KEY_KP8}, {XKB_KEY_KP_9, MP_KEY_KP9},
77     {XKB_KEY_KP_Decimal, MP_KEY_KPDEC}, {XKB_KEY_KP_Separator, MP_KEY_KPDEC},
78 
79     /* Numpad without numlock */
80     {XKB_KEY_KP_Insert, MP_KEY_KPINS}, {XKB_KEY_KP_End,       MP_KEY_KP1},
81     {XKB_KEY_KP_Down,   MP_KEY_KP2},   {XKB_KEY_KP_Page_Down, MP_KEY_KP3},
82     {XKB_KEY_KP_Left,   MP_KEY_KP4},   {XKB_KEY_KP_Begin,     MP_KEY_KP5},
83     {XKB_KEY_KP_Right,  MP_KEY_KP6},   {XKB_KEY_KP_Home,      MP_KEY_KP7},
84     {XKB_KEY_KP_Up,     MP_KEY_KP8},   {XKB_KEY_KP_Page_Up,   MP_KEY_KP9},
85     {XKB_KEY_KP_Delete, MP_KEY_KPDEL},
86 
87     /* Multimedia keys */
88     {XKB_KEY_XF86MenuKB, MP_KEY_MENU},
89     {XKB_KEY_XF86AudioPlay, MP_KEY_PLAY}, {XKB_KEY_XF86AudioPause, MP_KEY_PAUSE},
90     {XKB_KEY_XF86AudioStop, MP_KEY_STOP},
91     {XKB_KEY_XF86AudioPrev, MP_KEY_PREV}, {XKB_KEY_XF86AudioNext, MP_KEY_NEXT},
92     {XKB_KEY_XF86AudioRewind, MP_KEY_REWIND},
93     {XKB_KEY_XF86AudioForward, MP_KEY_FORWARD},
94     {XKB_KEY_XF86AudioMute, MP_KEY_MUTE},
95     {XKB_KEY_XF86AudioLowerVolume, MP_KEY_VOLUME_DOWN},
96     {XKB_KEY_XF86AudioRaiseVolume, MP_KEY_VOLUME_UP},
97     {XKB_KEY_XF86HomePage, MP_KEY_HOMEPAGE}, {XKB_KEY_XF86WWW, MP_KEY_WWW},
98     {XKB_KEY_XF86Mail, MP_KEY_MAIL}, {XKB_KEY_XF86Favorites, MP_KEY_FAVORITES},
99     {XKB_KEY_XF86Search, MP_KEY_SEARCH}, {XKB_KEY_XF86Sleep, MP_KEY_SLEEP},
100 
101     {0, 0}
102 };
103 
104 #define OPT_BASE_STRUCT struct wayland_opts
105 const struct m_sub_options wayland_conf = {
106     .opts = (const struct m_option[]) {
107         {"wayland-disable-vsync", OPT_FLAG(disable_vsync)},
108         {"wayland-edge-pixels-pointer", OPT_INT(edge_pixels_pointer),
109             M_RANGE(0, INT_MAX)},
110         {"wayland-edge-pixels-touch", OPT_INT(edge_pixels_touch),
111             M_RANGE(0, INT_MAX)},
112         {0},
113     },
114     .size = sizeof(struct wayland_opts),
115     .defaults = &(struct wayland_opts) {
116         .disable_vsync = false,
117         .edge_pixels_pointer = 10,
118         .edge_pixels_touch = 32,
119     },
120 };
121 
122 struct vo_wayland_output {
123     struct vo_wayland_state *wl;
124     struct wl_output *output;
125     struct mp_rect geometry;
126     bool has_surface;
127     uint32_t id;
128     uint32_t flags;
129     int phys_width;
130     int phys_height;
131     int scale;
132     double refresh_rate;
133     char *make;
134     char *model;
135     struct wl_list link;
136 };
137 
138 struct vo_wayland_sync {
139     int64_t ust;
140     int64_t msc;
141     int64_t sbc;
142     bool filled;
143 };
144 
145 static int check_for_resize(struct vo_wayland_state *wl, wl_fixed_t x_w, wl_fixed_t y_w,
146                             int edge_pixels, enum xdg_toplevel_resize_edge *edge);
147 static int get_mods(struct vo_wayland_state *wl);
148 static int last_available_sync(struct vo_wayland_state *wl);
149 static int lookupkey(int key);
150 static int set_cursor_visibility(struct vo_wayland_state *wl, bool on);
151 static int spawn_cursor(struct vo_wayland_state *wl);
152 
153 static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b);
154 static void queue_new_sync(struct vo_wayland_state *wl);
155 static void remove_output(struct vo_wayland_output *out);
156 static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode);
157 static void set_geometry(struct vo_wayland_state *wl);
158 static void set_surface_scaling(struct vo_wayland_state *wl);
159 static void sync_shift(struct vo_wayland_state *wl);
160 static void window_move(struct vo_wayland_state *wl, uint32_t serial);
161 
162 /* Wayland listener boilerplate */
pointer_handle_enter(void * data,struct wl_pointer * pointer,uint32_t serial,struct wl_surface * surface,wl_fixed_t sx,wl_fixed_t sy)163 static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
164                                  uint32_t serial, struct wl_surface *surface,
165                                  wl_fixed_t sx, wl_fixed_t sy)
166 {
167     struct vo_wayland_state *wl = data;
168 
169     wl->pointer    = pointer;
170     wl->pointer_id = serial;
171 
172     set_cursor_visibility(wl, wl->cursor_visible);
173     mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_ENTER);
174 }
175 
pointer_handle_leave(void * data,struct wl_pointer * pointer,uint32_t serial,struct wl_surface * surface)176 static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
177                                  uint32_t serial, struct wl_surface *surface)
178 {
179     struct vo_wayland_state *wl = data;
180     mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_LEAVE);
181 }
182 
pointer_handle_motion(void * data,struct wl_pointer * pointer,uint32_t time,wl_fixed_t sx,wl_fixed_t sy)183 static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
184                                   uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
185 {
186     struct vo_wayland_state *wl = data;
187 
188     wl->mouse_x = wl_fixed_to_int(sx) * wl->scaling;
189     wl->mouse_y = wl_fixed_to_int(sy) * wl->scaling;
190     wl->mouse_unscaled_x = sx;
191     wl->mouse_unscaled_y = sy;
192 
193     if (!wl->toplevel_configured)
194         mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
195     wl->toplevel_configured = false;
196 }
197 
pointer_handle_button(void * data,struct wl_pointer * wl_pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state)198 static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
199                                   uint32_t serial, uint32_t time, uint32_t button,
200                                   uint32_t state)
201 {
202     struct vo_wayland_state *wl = data;
203     int mpmod = 0;
204 
205     state = state == WL_POINTER_BUTTON_STATE_PRESSED ? MP_KEY_STATE_DOWN
206                                                      : MP_KEY_STATE_UP;
207 
208     switch (button) {
209     case BTN_LEFT:
210         button = MP_MBTN_LEFT;
211         break;
212     case BTN_MIDDLE:
213         button = MP_MBTN_MID;
214         break;
215     case BTN_RIGHT:
216         button = MP_MBTN_RIGHT;
217         break;
218     case BTN_SIDE:
219         button = MP_MBTN_BACK;
220         break;
221     case BTN_EXTRA:
222         button = MP_MBTN_FORWARD;
223         break;
224     default:
225         button = 0;
226         break;
227     }
228 
229     if (wl->keyboard)
230         mpmod = get_mods(wl);
231 
232     if (button)
233         mp_input_put_key(wl->vo->input_ctx, button | state | mpmod);
234 
235     if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) &&
236         (!wl->vo_opts->fullscreen) && (!wl->vo_opts->window_maximized) &&
237         (button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN)) {
238         uint32_t edges;
239         // Implement an edge resize zone if there are no decorations
240         if (!wl->xdg_toplevel_decoration &&
241             check_for_resize(wl, wl->mouse_unscaled_x, wl->mouse_unscaled_y,
242                              wl->opts->edge_pixels_pointer, &edges))
243             xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edges);
244         else
245             window_move(wl, serial);
246         // Explictly send an UP event after the client finishes a move/resize
247         mp_input_put_key(wl->vo->input_ctx, button | MP_KEY_STATE_UP);
248     }
249 }
250 
pointer_handle_axis(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis,wl_fixed_t value)251 static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
252                                 uint32_t time, uint32_t axis, wl_fixed_t value)
253 {
254     struct vo_wayland_state *wl = data;
255 
256     double val = wl_fixed_to_double(value) < 0 ? -1 : 1;
257     switch (axis) {
258     case WL_POINTER_AXIS_VERTICAL_SCROLL:
259         if (value > 0)
260             mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_DOWN,  +val);
261         if (value < 0)
262             mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP,    -val);
263         break;
264     case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
265         if (value > 0)
266             mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_RIGHT, +val);
267         if (value < 0)
268             mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT,  -val);
269         break;
270     }
271 }
272 
273 static const struct wl_pointer_listener pointer_listener = {
274     pointer_handle_enter,
275     pointer_handle_leave,
276     pointer_handle_motion,
277     pointer_handle_button,
278     pointer_handle_axis,
279 };
280 
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)281 static void touch_handle_down(void *data, struct wl_touch *wl_touch,
282                               uint32_t serial, uint32_t time, struct wl_surface *surface,
283                               int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
284 {
285     struct vo_wayland_state *wl = data;
286 
287     wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
288     wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
289 
290     mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
291     mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN);
292 
293     enum xdg_toplevel_resize_edge edge;
294     if (check_for_resize(wl, x_w, y_w, wl->opts->edge_pixels_touch, &edge)) {
295         xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edge);
296     } else {
297         xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
298     }
299 }
300 
touch_handle_up(void * data,struct wl_touch * wl_touch,uint32_t serial,uint32_t time,int32_t id)301 static void touch_handle_up(void *data, struct wl_touch *wl_touch,
302                             uint32_t serial, uint32_t time, int32_t id)
303 {
304     struct vo_wayland_state *wl = data;
305     mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP);
306 }
307 
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)308 static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
309                                 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
310 {
311     struct vo_wayland_state *wl = data;
312 
313     wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
314     wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
315 
316     mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
317 }
318 
touch_handle_frame(void * data,struct wl_touch * wl_touch)319 static void touch_handle_frame(void *data, struct wl_touch *wl_touch)
320 {
321 }
322 
touch_handle_cancel(void * data,struct wl_touch * wl_touch)323 static void touch_handle_cancel(void *data, struct wl_touch *wl_touch)
324 {
325 }
326 
327 static const struct wl_touch_listener touch_listener = {
328     touch_handle_down,
329     touch_handle_up,
330     touch_handle_motion,
331     touch_handle_frame,
332     touch_handle_cancel,
333 };
334 
keyboard_handle_keymap(void * data,struct wl_keyboard * wl_keyboard,uint32_t format,int32_t fd,uint32_t size)335 static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
336                                    uint32_t format, int32_t fd, uint32_t size)
337 {
338     struct vo_wayland_state *wl = data;
339     char *map_str;
340 
341     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
342         close(fd);
343         return;
344     }
345 
346     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
347     if (map_str == MAP_FAILED) {
348         close(fd);
349         return;
350     }
351 
352     wl->xkb_keymap = xkb_keymap_new_from_string(wl->xkb_context, map_str,
353                                                 XKB_KEYMAP_FORMAT_TEXT_V1, 0);
354 
355     munmap(map_str, size);
356     close(fd);
357 
358     if (!wl->xkb_keymap) {
359         MP_ERR(wl, "failed to compile keymap\n");
360         return;
361     }
362 
363     wl->xkb_state = xkb_state_new(wl->xkb_keymap);
364     if (!wl->xkb_state) {
365         MP_ERR(wl, "failed to create XKB state\n");
366         xkb_keymap_unref(wl->xkb_keymap);
367         wl->xkb_keymap = NULL;
368         return;
369     }
370 }
371 
keyboard_handle_enter(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)372 static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
373                                   uint32_t serial, struct wl_surface *surface,
374                                   struct wl_array *keys)
375 {
376     struct vo_wayland_state *wl = data;
377     wl->has_keyboard_input = true;
378 }
379 
keyboard_handle_leave(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface)380 static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
381                                   uint32_t serial, struct wl_surface *surface)
382 {
383     struct vo_wayland_state *wl = data;
384     wl->has_keyboard_input = false;
385 }
386 
keyboard_handle_key(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)387 static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
388                                 uint32_t serial, uint32_t time, uint32_t key,
389                                 uint32_t state)
390 {
391     struct vo_wayland_state *wl = data;
392 
393     wl->keyboard_code = key + 8;
394     xkb_keysym_t sym = xkb_state_key_get_one_sym(wl->xkb_state, wl->keyboard_code);
395 
396     state = state == WL_KEYBOARD_KEY_STATE_PRESSED ? MP_KEY_STATE_DOWN
397                                                    : MP_KEY_STATE_UP;
398     int mpmod = get_mods(wl);
399     int mpkey = lookupkey(sym);
400     if (mpkey) {
401         mp_input_put_key(wl->vo->input_ctx, mpkey | state | mpmod);
402     } else {
403         char s[128];
404         if (xkb_keysym_to_utf8(sym, s, sizeof(s)) > 0)
405             mp_input_put_key_utf8(wl->vo->input_ctx, state | mpmod, bstr0(s));
406     }
407 }
408 
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)409 static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
410                                       uint32_t serial, uint32_t mods_depressed,
411                                       uint32_t mods_latched, uint32_t mods_locked,
412                                       uint32_t group)
413 {
414     struct vo_wayland_state *wl = data;
415 
416     if (wl->xkb_state) {
417         xkb_state_update_mask(wl->xkb_state, mods_depressed, mods_latched,
418                               mods_locked, 0, 0, group);
419     }
420 }
421 
keyboard_handle_repeat_info(void * data,struct wl_keyboard * wl_keyboard,int32_t rate,int32_t delay)422 static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
423                                         int32_t rate, int32_t delay)
424 {
425     struct vo_wayland_state *wl = data;
426     if (wl->vo_opts->native_keyrepeat)
427         mp_input_set_repeat_info(wl->vo->input_ctx, rate, delay);
428 }
429 
430 static const struct wl_keyboard_listener keyboard_listener = {
431     keyboard_handle_keymap,
432     keyboard_handle_enter,
433     keyboard_handle_leave,
434     keyboard_handle_key,
435     keyboard_handle_modifiers,
436     keyboard_handle_repeat_info,
437 };
438 
seat_handle_caps(void * data,struct wl_seat * seat,enum wl_seat_capability caps)439 static void seat_handle_caps(void *data, struct wl_seat *seat,
440                              enum wl_seat_capability caps)
441 {
442     struct vo_wayland_state *wl = data;
443 
444     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl->pointer) {
445         wl->pointer = wl_seat_get_pointer(seat);
446         wl_pointer_add_listener(wl->pointer, &pointer_listener, wl);
447     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->pointer) {
448         wl_pointer_destroy(wl->pointer);
449         wl->pointer = NULL;
450     }
451 
452     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl->keyboard) {
453         wl->keyboard = wl_seat_get_keyboard(seat);
454         wl_keyboard_add_listener(wl->keyboard, &keyboard_listener, wl);
455     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl->keyboard) {
456         wl_keyboard_destroy(wl->keyboard);
457         wl->keyboard = NULL;
458     }
459 
460     if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wl->touch) {
461         wl->touch = wl_seat_get_touch(seat);
462         wl_touch_set_user_data(wl->touch, wl);
463         wl_touch_add_listener(wl->touch, &touch_listener, wl);
464     } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wl->touch) {
465         wl_touch_destroy(wl->touch);
466         wl->touch = NULL;
467     }
468 }
469 
470 static const struct wl_seat_listener seat_listener = {
471     seat_handle_caps,
472 };
473 
data_offer_handle_offer(void * data,struct wl_data_offer * offer,const char * mime_type)474 static void data_offer_handle_offer(void *data, struct wl_data_offer *offer,
475                                     const char *mime_type)
476 {
477     struct vo_wayland_state *wl = data;
478     int score = mp_event_get_mime_type_score(wl->vo->input_ctx, mime_type);
479     if (score > wl->dnd_mime_score) {
480         wl->dnd_mime_score = score;
481         talloc_free(wl->dnd_mime_type);
482         wl->dnd_mime_type = talloc_strdup(wl, mime_type);
483         MP_VERBOSE(wl, "Given DND offer with mime type %s\n", wl->dnd_mime_type);
484     }
485 }
486 
data_offer_source_actions(void * data,struct wl_data_offer * offer,uint32_t source_actions)487 static void data_offer_source_actions(void *data, struct wl_data_offer *offer, uint32_t source_actions)
488 {
489 }
490 
data_offer_action(void * data,struct wl_data_offer * wl_data_offer,uint32_t dnd_action)491 static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action)
492 {
493     struct vo_wayland_state *wl = data;
494     wl->dnd_action = dnd_action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ?
495                      DND_REPLACE : DND_APPEND;
496     MP_VERBOSE(wl, "DND action is %s\n",
497                wl->dnd_action == DND_REPLACE ? "DND_REPLACE" : "DND_APPEND");
498 }
499 
500 static const struct wl_data_offer_listener data_offer_listener = {
501     data_offer_handle_offer,
502     data_offer_source_actions,
503     data_offer_action,
504 };
505 
data_device_handle_data_offer(void * data,struct wl_data_device * wl_ddev,struct wl_data_offer * id)506 static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_ddev,
507                                           struct wl_data_offer *id)
508 {
509     struct vo_wayland_state *wl = data;
510     if (wl->dnd_offer)
511         wl_data_offer_destroy(wl->dnd_offer);
512 
513     wl->dnd_offer = id;
514     wl_data_offer_add_listener(id, &data_offer_listener, wl);
515 }
516 
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)517 static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev,
518                                      uint32_t serial, struct wl_surface *surface,
519                                      wl_fixed_t x, wl_fixed_t y,
520                                      struct wl_data_offer *id)
521 {
522     struct vo_wayland_state *wl = data;
523     if (wl->dnd_offer != id) {
524         MP_FATAL(wl, "DND offer ID mismatch!\n");
525         return;
526     }
527 
528     wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
529                                   WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
530                                   WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
531 
532     wl_data_offer_accept(id, serial, wl->dnd_mime_type);
533 
534     MP_VERBOSE(wl, "Accepting DND offer with mime type %s\n", wl->dnd_mime_type);
535 }
536 
data_device_handle_leave(void * data,struct wl_data_device * wl_ddev)537 static void data_device_handle_leave(void *data, struct wl_data_device *wl_ddev)
538 {
539     struct vo_wayland_state *wl = data;
540 
541     if (wl->dnd_offer) {
542         if (wl->dnd_fd != -1)
543             return;
544         wl_data_offer_destroy(wl->dnd_offer);
545         wl->dnd_offer = NULL;
546     }
547 
548     MP_VERBOSE(wl, "Releasing DND offer with mime type %s\n", wl->dnd_mime_type);
549 
550     talloc_free(wl->dnd_mime_type);
551     wl->dnd_mime_type = NULL;
552     wl->dnd_mime_score = 0;
553 }
554 
data_device_handle_motion(void * data,struct wl_data_device * wl_ddev,uint32_t time,wl_fixed_t x,wl_fixed_t y)555 static void data_device_handle_motion(void *data, struct wl_data_device *wl_ddev,
556                                       uint32_t time, wl_fixed_t x, wl_fixed_t y)
557 {
558     struct vo_wayland_state *wl = data;
559 
560     wl_data_offer_accept(wl->dnd_offer, time, wl->dnd_mime_type);
561 }
562 
data_device_handle_drop(void * data,struct wl_data_device * wl_ddev)563 static void data_device_handle_drop(void *data, struct wl_data_device *wl_ddev)
564 {
565     struct vo_wayland_state *wl = data;
566 
567     int pipefd[2];
568 
569     if (pipe2(pipefd, O_CLOEXEC) == -1) {
570         MP_ERR(wl, "Failed to create dnd pipe!\n");
571         return;
572     }
573 
574     MP_VERBOSE(wl, "Receiving DND offer with mime %s\n", wl->dnd_mime_type);
575 
576     wl_data_offer_receive(wl->dnd_offer, wl->dnd_mime_type, pipefd[1]);
577     close(pipefd[1]);
578 
579     wl->dnd_fd = pipefd[0];
580     wl_data_offer_finish(wl->dnd_offer);
581 }
582 
data_device_handle_selection(void * data,struct wl_data_device * wl_ddev,struct wl_data_offer * id)583 static void data_device_handle_selection(void *data, struct wl_data_device *wl_ddev,
584                                          struct wl_data_offer *id)
585 {
586 }
587 
588 static const struct wl_data_device_listener data_device_listener = {
589     data_device_handle_data_offer,
590     data_device_handle_enter,
591     data_device_handle_leave,
592     data_device_handle_motion,
593     data_device_handle_drop,
594     data_device_handle_selection,
595 };
596 
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)597 static void output_handle_geometry(void *data, struct wl_output *wl_output,
598                                    int32_t x, int32_t y, int32_t phys_width,
599                                    int32_t phys_height, int32_t subpixel,
600                                    const char *make, const char *model,
601                                    int32_t transform)
602 {
603     struct vo_wayland_output *output = data;
604     output->make = talloc_strdup(output->wl, make);
605     output->model = talloc_strdup(output->wl, model);
606     output->geometry.x0 = x;
607     output->geometry.y0 = y;
608     output->phys_width = phys_width;
609     output->phys_height = phys_height;
610 }
611 
output_handle_mode(void * data,struct wl_output * wl_output,uint32_t flags,int32_t width,int32_t height,int32_t refresh)612 static void output_handle_mode(void *data, struct wl_output *wl_output,
613                                uint32_t flags, int32_t width,
614                                int32_t height, int32_t refresh)
615 {
616     struct vo_wayland_output *output = data;
617 
618     /* Only save current mode */
619     if (!(flags & WL_OUTPUT_MODE_CURRENT))
620         return;
621 
622     output->geometry.x1 = width;
623     output->geometry.y1 = height;
624     output->flags = flags;
625     output->refresh_rate = (double)refresh * 0.001;
626 }
627 
output_handle_done(void * data,struct wl_output * wl_output)628 static void output_handle_done(void* data, struct wl_output *wl_output)
629 {
630     struct vo_wayland_output *o = data;
631     struct vo_wayland_state *wl = o->wl;
632 
633     o->geometry.x1 += o->geometry.x0;
634     o->geometry.y1 += o->geometry.y0;
635 
636     MP_VERBOSE(o->wl, "Registered output %s %s (0x%x):\n"
637                "\tx: %dpx, y: %dpx\n"
638                "\tw: %dpx (%dmm), h: %dpx (%dmm)\n"
639                "\tscale: %d\n"
640                "\tHz: %f\n", o->make, o->model, o->id, o->geometry.x0,
641                o->geometry.y0, mp_rect_w(o->geometry), o->phys_width,
642                mp_rect_h(o->geometry), o->phys_height, o->scale, o->refresh_rate);
643 
644     /* If we satisfy this conditional, something about the current
645      * output must have changed (resolution, scale, etc). All window
646      * geometry and scaling should be recalculated. */
647     if (wl->current_output && wl->current_output->output == wl_output) {
648         set_surface_scaling(wl);
649         if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) {
650             wl_surface_set_buffer_scale(wl->surface, wl->scaling);
651         } else {
652             wl->scale_change = true;
653         }
654         spawn_cursor(wl);
655         set_geometry(wl);
656         wl->pending_vo_events |= VO_EVENT_DPI;
657         wl->pending_vo_events |= VO_EVENT_RESIZE;
658     }
659 
660     wl->pending_vo_events |= VO_EVENT_WIN_STATE;
661 }
662 
output_handle_scale(void * data,struct wl_output * wl_output,int32_t factor)663 static void output_handle_scale(void* data, struct wl_output *wl_output,
664                                 int32_t factor)
665 {
666     struct vo_wayland_output *output = data;
667     if (!factor) {
668         MP_ERR(output->wl, "Invalid output scale given by the compositor!\n");
669         return;
670     }
671     output->scale = factor;
672 }
673 
674 static const struct wl_output_listener output_listener = {
675     output_handle_geometry,
676     output_handle_mode,
677     output_handle_done,
678     output_handle_scale,
679 };
680 
surface_handle_enter(void * data,struct wl_surface * wl_surface,struct wl_output * output)681 static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
682                                  struct wl_output *output)
683 {
684     struct vo_wayland_state *wl = data;
685     if (!wl->current_output)
686         return;
687 
688     struct mp_rect old_output_geometry = wl->current_output->geometry;
689     struct mp_rect old_geometry = wl->geometry;
690     wl->current_output = NULL;
691 
692     struct vo_wayland_output *o;
693     wl_list_for_each(o, &wl->output_list, link) {
694         if (o->output == output) {
695             wl->current_output = o;
696             break;
697         }
698     }
699 
700     wl->current_output->has_surface = true;
701     bool force_resize = false;
702 
703     if (wl->scaling != wl->current_output->scale) {
704         set_surface_scaling(wl);
705         if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) {
706             wl->scale_change = true;
707         } else {
708             wl_surface_set_buffer_scale(wl->surface, wl->scaling);
709         }
710         spawn_cursor(wl);
711         wl->pending_vo_events |= VO_EVENT_DPI;
712     }
713 
714     if (!mp_rect_equals(&old_output_geometry, &wl->current_output->geometry)) {
715         set_geometry(wl);
716         force_resize = true;
717     }
718 
719     if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize)
720         wl->pending_vo_events |= VO_EVENT_RESIZE;
721 
722     MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %i\n", o->make,
723                o->model, o->id, wl->scaling);
724 
725     wl->pending_vo_events |= VO_EVENT_WIN_STATE;
726 }
727 
surface_handle_leave(void * data,struct wl_surface * wl_surface,struct wl_output * output)728 static void surface_handle_leave(void *data, struct wl_surface *wl_surface,
729                                  struct wl_output *output)
730 {
731     struct vo_wayland_state *wl = data;
732 
733     struct vo_wayland_output *o;
734     wl_list_for_each(o, &wl->output_list, link) {
735         if (o->output == output) {
736             o->has_surface = false;
737             wl->pending_vo_events |= VO_EVENT_WIN_STATE;
738             return;
739         }
740     }
741 }
742 
743 static const struct wl_surface_listener surface_listener = {
744     surface_handle_enter,
745     surface_handle_leave,
746 };
747 
xdg_wm_base_ping(void * data,struct xdg_wm_base * wm_base,uint32_t serial)748 static void xdg_wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
749 {
750     xdg_wm_base_pong(wm_base, serial);
751 }
752 
753 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
754     xdg_wm_base_ping,
755 };
756 
handle_surface_config(void * data,struct xdg_surface * surface,uint32_t serial)757 static void handle_surface_config(void *data, struct xdg_surface *surface,
758                                   uint32_t serial)
759 {
760     xdg_surface_ack_configure(surface, serial);
761 }
762 
763 static const struct xdg_surface_listener xdg_surface_listener = {
764     handle_surface_config,
765 };
766 
handle_toplevel_config(void * data,struct xdg_toplevel * toplevel,int32_t width,int32_t height,struct wl_array * states)767 static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
768                                    int32_t width, int32_t height, struct wl_array *states)
769 {
770     struct vo_wayland_state *wl = data;
771     struct mp_vo_opts *vo_opts = wl->vo_opts;
772     struct mp_rect old_geometry = wl->geometry;
773 
774     int old_toplevel_width = wl->toplevel_width;
775     int old_toplevel_height = wl->toplevel_height;
776     wl->toplevel_width = width;
777     wl->toplevel_height = height;
778 
779     /* Don't do anything here if we haven't finished setting geometry. */
780     if (mp_rect_w(wl->geometry) == 0 || mp_rect_h(wl->geometry) == 0)
781         return;
782 
783     bool is_maximized = false;
784     bool is_fullscreen = false;
785     bool is_activated = false;
786     enum xdg_toplevel_state *state;
787     wl_array_for_each(state, states) {
788         switch (*state) {
789         case XDG_TOPLEVEL_STATE_FULLSCREEN:
790             is_fullscreen = true;
791             break;
792         case XDG_TOPLEVEL_STATE_RESIZING:
793             break;
794         case XDG_TOPLEVEL_STATE_ACTIVATED:
795             is_activated = true;
796             /*
797              * If we get an ACTIVATED state, we know it cannot be
798              * minimized, but it may not have been minimized
799              * previously, so we can't detect the exact state.
800              */
801             vo_opts->window_minimized = false;
802             m_config_cache_write_opt(wl->vo_opts_cache,
803                                      &vo_opts->window_minimized);
804             break;
805         case XDG_TOPLEVEL_STATE_TILED_TOP:
806         case XDG_TOPLEVEL_STATE_TILED_LEFT:
807         case XDG_TOPLEVEL_STATE_TILED_RIGHT:
808         case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
809         case XDG_TOPLEVEL_STATE_MAXIMIZED:
810             is_maximized = true;
811             break;
812         }
813     }
814 
815     if (vo_opts->fullscreen != is_fullscreen) {
816         wl->state_change = true;
817         vo_opts->fullscreen = is_fullscreen;
818         m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->fullscreen);
819     }
820 
821     if (vo_opts->window_maximized != is_maximized) {
822         wl->state_change = true;
823         vo_opts->window_maximized = is_maximized;
824         m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->window_maximized);
825     }
826 
827     if (wl->requested_decoration)
828         request_decoration_mode(wl, wl->requested_decoration);
829 
830     if (wl->activated != is_activated) {
831         wl->activated = is_activated;
832         if ((!wl->focused && wl->activated && wl->has_keyboard_input) ||
833             (wl->focused && !wl->activated))
834         {
835             wl->focused = !wl->focused;
836             wl->pending_vo_events |= VO_EVENT_FOCUS;
837         }
838         /* Just force a redraw to be on the safe side. */
839         if (wl->activated) {
840             wl->hidden = false;
841             wl->pending_vo_events |= VO_EVENT_EXPOSE;
842         }
843     }
844 
845     if (wl->scale_change) {
846         wl_surface_set_buffer_scale(wl->surface, wl->scaling);
847         wl->scale_change = false;
848     }
849 
850     if (wl->state_change) {
851         if (!is_fullscreen && !is_maximized) {
852             wl->geometry = wl->window_size;
853             wl->state_change = false;
854             goto resize;
855         }
856     }
857 
858     if (old_toplevel_width == wl->toplevel_width &&
859         old_toplevel_height == wl->toplevel_height)
860         return;
861 
862     if (!is_fullscreen && !is_maximized) {
863         if (vo_opts->keepaspect) {
864             double scale_factor = (double)width / wl->reduced_width;
865             width = ceil(wl->reduced_width * scale_factor);
866             if (vo_opts->keepaspect_window)
867                 height = ceil(wl->reduced_height * scale_factor);
868         }
869         wl->window_size.x0 = 0;
870         wl->window_size.y0 = 0;
871         wl->window_size.x1 = width;
872         wl->window_size.y1 = height;
873     }
874     wl->geometry.x0 = 0;
875     wl->geometry.y0 = 0;
876     wl->geometry.x1 = width;
877     wl->geometry.y1 = height;
878 
879     if (mp_rect_equals(&old_geometry, &wl->geometry))
880         return;
881 
882 resize:
883     MP_VERBOSE(wl, "Resizing due to xdg from %ix%i to %ix%i\n",
884                mp_rect_w(old_geometry)*wl->scaling, mp_rect_h(old_geometry)*wl->scaling,
885                mp_rect_w(wl->geometry)*wl->scaling, mp_rect_h(wl->geometry)*wl->scaling);
886 
887     wl->pending_vo_events |= VO_EVENT_RESIZE;
888     wl->toplevel_configured = true;
889 }
890 
handle_toplevel_close(void * data,struct xdg_toplevel * xdg_toplevel)891 static void handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
892 {
893     struct vo_wayland_state *wl = data;
894     mp_input_put_key(wl->vo->input_ctx, MP_KEY_CLOSE_WIN);
895 }
896 
897 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
898     handle_toplevel_config,
899     handle_toplevel_close,
900 };
901 
configure_decorations(void * data,struct zxdg_toplevel_decoration_v1 * xdg_toplevel_decoration,uint32_t mode)902 static void configure_decorations(void *data,
903                                   struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration,
904                                   uint32_t mode)
905 {
906     struct vo_wayland_state *wl = data;
907     struct mp_vo_opts *opts = wl->vo_opts;
908 
909     if (wl->requested_decoration == mode)
910         wl->requested_decoration = 0;
911 
912     if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) {
913         MP_VERBOSE(wl, "Enabling server decorations\n");
914     } else {
915         MP_VERBOSE(wl, "Disabling server decorations\n");
916     }
917     opts->border = mode - 1;
918     m_config_cache_write_opt(wl->vo_opts_cache, &opts->border);
919 }
920 
921 static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
922     configure_decorations,
923 };
924 
pres_set_clockid(void * data,struct wp_presentation * pres,uint32_t clockid)925 static void pres_set_clockid(void *data, struct wp_presentation *pres,
926                            uint32_t clockid)
927 {
928     struct vo_wayland_state *wl = data;
929 
930     if (clockid == CLOCK_MONOTONIC)
931         wl->presentation = pres;
932 }
933 
934 static const struct wp_presentation_listener pres_listener = {
935     pres_set_clockid,
936 };
937 
feedback_sync_output(void * data,struct wp_presentation_feedback * fback,struct wl_output * output)938 static void feedback_sync_output(void *data, struct wp_presentation_feedback *fback,
939                                struct wl_output *output)
940 {
941 }
942 
feedback_presented(void * data,struct wp_presentation_feedback * fback,uint32_t tv_sec_hi,uint32_t tv_sec_lo,uint32_t tv_nsec,uint32_t refresh_nsec,uint32_t seq_hi,uint32_t seq_lo,uint32_t flags)943 static void feedback_presented(void *data, struct wp_presentation_feedback *fback,
944                               uint32_t tv_sec_hi, uint32_t tv_sec_lo,
945                               uint32_t tv_nsec, uint32_t refresh_nsec,
946                               uint32_t seq_hi, uint32_t seq_lo,
947                               uint32_t flags)
948 {
949     struct vo_wayland_state *wl = data;
950     sync_shift(wl);
951 
952     if (fback)
953         wp_presentation_feedback_destroy(fback);
954 
955     wl->refresh_interval = (int64_t)refresh_nsec / 1000;
956 
957     // Very similar to oml_sync_control, in this case we assume that every
958     // time the compositor receives feedback, a buffer swap has been already
959     // been performed.
960     //
961     // Notes:
962     //  - tv_sec_lo + tv_sec_hi is the equivalent of oml's ust
963     //  - seq_lo + seq_hi is the equivalent of oml's msc
964     //  - these values are updated everytime the compositor receives feedback.
965 
966     int index = last_available_sync(wl);
967     if (index < 0) {
968         queue_new_sync(wl);
969         index = 0;
970     }
971     int64_t sec = (uint64_t) tv_sec_lo + ((uint64_t) tv_sec_hi << 32);
972     wl->sync[index].ust = sec * 1000000LL + (uint64_t) tv_nsec / 1000;
973     wl->sync[index].msc = (uint64_t) seq_lo + ((uint64_t) seq_hi << 32);
974     wl->sync[index].filled = true;
975 }
976 
feedback_discarded(void * data,struct wp_presentation_feedback * fback)977 static void feedback_discarded(void *data, struct wp_presentation_feedback *fback)
978 {
979 }
980 
981 static const struct wp_presentation_feedback_listener feedback_listener = {
982     feedback_sync_output,
983     feedback_presented,
984     feedback_discarded,
985 };
986 
987 static const struct wl_callback_listener frame_listener;
988 
frame_callback(void * data,struct wl_callback * callback,uint32_t time)989 static void frame_callback(void *data, struct wl_callback *callback, uint32_t time)
990 {
991     struct vo_wayland_state *wl = data;
992 
993     if (callback)
994         wl_callback_destroy(callback);
995 
996     wl->frame_callback = wl_surface_frame(wl->surface);
997     wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
998 
999     if (wl->presentation) {
1000         wl->feedback = wp_presentation_feedback(wl->presentation, wl->surface);
1001         wp_presentation_feedback_add_listener(wl->feedback, &feedback_listener, wl);
1002     }
1003 
1004     wl->frame_wait = false;
1005     wl->hidden = false;
1006 }
1007 
1008 static const struct wl_callback_listener frame_listener = {
1009     frame_callback,
1010 };
1011 
registry_handle_add(void * data,struct wl_registry * reg,uint32_t id,const char * interface,uint32_t ver)1012 static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id,
1013                                 const char *interface, uint32_t ver)
1014 {
1015     int found = 1;
1016     struct vo_wayland_state *wl = data;
1017 
1018     if (!strcmp(interface, wl_compositor_interface.name) && (ver >= 3) && found++) {
1019         wl->compositor = wl_registry_bind(reg, id, &wl_compositor_interface, 3);
1020         wl->surface = wl_compositor_create_surface(wl->compositor);
1021         wl->cursor_surface = wl_compositor_create_surface(wl->compositor);
1022         wl_surface_add_listener(wl->surface, &surface_listener, wl);
1023     }
1024 
1025     if (!strcmp(interface, wl_data_device_manager_interface.name) && (ver >= 3) && found++) {
1026         wl->dnd_devman = wl_registry_bind(reg, id, &wl_data_device_manager_interface, 3);
1027     }
1028 
1029     if (!strcmp(interface, wl_output_interface.name) && (ver >= 2) && found++) {
1030         struct vo_wayland_output *output = talloc_zero(wl, struct vo_wayland_output);
1031 
1032         output->wl     = wl;
1033         output->id     = id;
1034         output->scale  = 1;
1035         output->output = wl_registry_bind(reg, id, &wl_output_interface, 2);
1036 
1037         wl_output_add_listener(output->output, &output_listener, output);
1038         wl_list_insert(&wl->output_list, &output->link);
1039     }
1040 
1041     if (!strcmp(interface, wl_seat_interface.name) && found++) {
1042         wl->seat = wl_registry_bind(reg, id, &wl_seat_interface, 1);
1043         wl_seat_add_listener(wl->seat, &seat_listener, wl);
1044     }
1045 
1046     if (!strcmp(interface, wl_shm_interface.name) && found++) {
1047         wl->shm = wl_registry_bind(reg, id, &wl_shm_interface, 1);
1048     }
1049 
1050     if (!strcmp(interface, wp_presentation_interface.name) && found++) {
1051         wl->presentation = wl_registry_bind(reg, id, &wp_presentation_interface, 1);
1052         wp_presentation_add_listener(wl->presentation, &pres_listener, wl);
1053     }
1054 
1055     if (!strcmp(interface, xdg_wm_base_interface.name) && found++) {
1056         ver = MPMIN(ver, 2); /* We can use either 1 or 2 */
1057         wl->wm_base = wl_registry_bind(reg, id, &xdg_wm_base_interface, ver);
1058         xdg_wm_base_add_listener(wl->wm_base, &xdg_wm_base_listener, wl);
1059     }
1060 
1061     if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name) && found++) {
1062         wl->xdg_decoration_manager = wl_registry_bind(reg, id, &zxdg_decoration_manager_v1_interface, 1);
1063     }
1064 
1065     if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) && found++) {
1066         wl->idle_inhibit_manager = wl_registry_bind(reg, id, &zwp_idle_inhibit_manager_v1_interface, 1);
1067     }
1068 
1069     if (found > 1)
1070         MP_VERBOSE(wl, "Registered for protocol %s\n", interface);
1071 }
1072 
registry_handle_remove(void * data,struct wl_registry * reg,uint32_t id)1073 static void registry_handle_remove(void *data, struct wl_registry *reg, uint32_t id)
1074 {
1075     struct vo_wayland_state *wl = data;
1076     struct vo_wayland_output *output, *tmp;
1077     wl_list_for_each_safe(output, tmp, &wl->output_list, link) {
1078         if (output->id == id) {
1079             remove_output(output);
1080             return;
1081         }
1082     }
1083 }
1084 
1085 static const struct wl_registry_listener registry_listener = {
1086     registry_handle_add,
1087     registry_handle_remove,
1088 };
1089 
1090 /* Static functions */
check_dnd_fd(struct vo_wayland_state * wl)1091 static void check_dnd_fd(struct vo_wayland_state *wl)
1092 {
1093     if (wl->dnd_fd == -1)
1094         return;
1095 
1096     struct pollfd fdp = { wl->dnd_fd, POLLIN | POLLERR | POLLHUP, 0 };
1097     if (poll(&fdp, 1, 0) <= 0)
1098         return;
1099 
1100     if (fdp.revents & POLLIN) {
1101         ptrdiff_t offset = 0;
1102         size_t data_read = 0;
1103         const size_t chunk_size = 1;
1104         uint8_t *buffer = ta_zalloc_size(wl, chunk_size);
1105         if (!buffer)
1106             goto end;
1107 
1108         while ((data_read = read(wl->dnd_fd, buffer + offset, chunk_size)) > 0) {
1109             offset += data_read;
1110             buffer = ta_realloc_size(wl, buffer, offset + chunk_size);
1111             memset(buffer + offset, 0, chunk_size);
1112             if (!buffer)
1113                 goto end;
1114         }
1115 
1116         MP_VERBOSE(wl, "Read %td bytes from the DND fd\n", offset);
1117 
1118         struct bstr file_list = bstr0(buffer);
1119         mp_event_drop_mime_data(wl->vo->input_ctx, wl->dnd_mime_type,
1120                                 file_list, wl->dnd_action);
1121         talloc_free(buffer);
1122 end:
1123         talloc_free(wl->dnd_mime_type);
1124         wl->dnd_mime_type = NULL;
1125         wl->dnd_mime_score = 0;
1126     }
1127 
1128     if (fdp.revents & (POLLIN | POLLERR | POLLHUP)) {
1129         close(wl->dnd_fd);
1130         wl->dnd_fd = -1;
1131     }
1132 }
1133 
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)1134 static int check_for_resize(struct vo_wayland_state *wl, wl_fixed_t x_w, wl_fixed_t y_w,
1135                             int edge_pixels, enum xdg_toplevel_resize_edge *edge)
1136 {
1137     if (wl->vo_opts->fullscreen || wl->vo_opts->window_maximized)
1138         return 0;
1139 
1140     int pos[2] = { wl_fixed_to_double(x_w), wl_fixed_to_double(y_w) };
1141     int left_edge   = pos[0] < edge_pixels;
1142     int top_edge    = pos[1] < edge_pixels;
1143     int right_edge  = pos[0] > (mp_rect_w(wl->geometry) - edge_pixels);
1144     int bottom_edge = pos[1] > (mp_rect_h(wl->geometry) - edge_pixels);
1145 
1146     if (left_edge) {
1147         *edge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
1148         if (top_edge)
1149             *edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
1150         else if (bottom_edge)
1151             *edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
1152     } else if (right_edge) {
1153         *edge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
1154         if (top_edge)
1155             *edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
1156         else if (bottom_edge)
1157             *edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
1158     } else if (top_edge) {
1159         *edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
1160     } else if (bottom_edge) {
1161         *edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
1162     } else {
1163         *edge = 0;
1164         return 0;
1165     }
1166 
1167     return 1;
1168 }
1169 
create_input(struct vo_wayland_state * wl)1170 static bool create_input(struct vo_wayland_state *wl)
1171 {
1172     wl->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1173 
1174     if (!wl->xkb_context) {
1175         MP_ERR(wl, "failed to initialize input: check xkbcommon\n");
1176         return 1;
1177     }
1178 
1179     return 0;
1180 }
1181 
create_xdg_surface(struct vo_wayland_state * wl)1182 static int create_xdg_surface(struct vo_wayland_state *wl)
1183 {
1184     wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->wm_base, wl->surface);
1185     xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
1186 
1187     wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
1188     xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);
1189 
1190     if (!wl->xdg_surface || !wl->xdg_toplevel)
1191         return 1;
1192     return 0;
1193 }
1194 
do_minimize(struct vo_wayland_state * wl)1195 static void do_minimize(struct vo_wayland_state *wl)
1196 {
1197     if (!wl->xdg_toplevel)
1198         return;
1199     if (wl->vo_opts->window_minimized)
1200         xdg_toplevel_set_minimized(wl->xdg_toplevel);
1201 }
1202 
get_displays_spanned(struct vo_wayland_state * wl)1203 static char **get_displays_spanned(struct vo_wayland_state *wl)
1204 {
1205     char **names = NULL;
1206     int displays_spanned = 0;
1207     struct vo_wayland_output *output;
1208     wl_list_for_each(output, &wl->output_list, link) {
1209         if (output->has_surface)
1210             MP_TARRAY_APPEND(NULL, names, displays_spanned,
1211                              talloc_strdup(NULL, output->model));
1212     }
1213     MP_TARRAY_APPEND(NULL, names, displays_spanned, NULL);
1214     return names;
1215 }
1216 
get_mods(struct vo_wayland_state * wl)1217 static int get_mods(struct vo_wayland_state *wl)
1218 {
1219     static char* const mod_names[] = {
1220         XKB_MOD_NAME_SHIFT,
1221         XKB_MOD_NAME_CTRL,
1222         XKB_MOD_NAME_ALT,
1223         XKB_MOD_NAME_LOGO,
1224     };
1225 
1226     static const int mods[] = {
1227         MP_KEY_MODIFIER_SHIFT,
1228         MP_KEY_MODIFIER_CTRL,
1229         MP_KEY_MODIFIER_ALT,
1230         MP_KEY_MODIFIER_META,
1231     };
1232 
1233     int modifiers = 0;
1234 
1235     for (int n = 0; n < MP_ARRAY_SIZE(mods); n++) {
1236         xkb_mod_index_t index = xkb_keymap_mod_get_index(wl->xkb_keymap, mod_names[n]);
1237         if (!xkb_state_mod_index_is_consumed(wl->xkb_state, wl->keyboard_code, index)
1238             && xkb_state_mod_index_is_active(wl->xkb_state, index,
1239                                              XKB_STATE_MODS_DEPRESSED))
1240             modifiers |= mods[n];
1241     }
1242     return modifiers;
1243 }
1244 
greatest_common_divisor(struct vo_wayland_state * wl,int a,int b)1245 static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b) {
1246     // euclidean algorithm
1247     int larger;
1248     int smaller;
1249     if (a > b) {
1250         larger = a;
1251         smaller = b;
1252     } else {
1253         larger = b;
1254         smaller = a;
1255     }
1256     int remainder = larger - smaller * floor(larger/smaller);
1257     if (remainder == 0) {
1258         wl->gcd = smaller;
1259     } else {
1260         greatest_common_divisor(wl, smaller, remainder);
1261     }
1262 }
1263 
find_output(struct vo_wayland_state * wl)1264 static struct vo_wayland_output *find_output(struct vo_wayland_state *wl)
1265 {
1266     int index = 0;
1267     int screen_id = wl->vo_opts->fsscreen_id;
1268     char *screen_name = wl->vo_opts->fsscreen_name;
1269     struct vo_wayland_output *output = NULL;
1270     struct vo_wayland_output *fallback_output = NULL;
1271     wl_list_for_each(output, &wl->output_list, link) {
1272         if (index == 0)
1273             fallback_output = output;
1274         if (screen_id == -1 && !screen_name)
1275             return output;
1276         if (screen_id == -1 && screen_name && !strcmp(screen_name, output->model))
1277             return output;
1278         if (screen_id == index++)
1279             return output;
1280     }
1281     if (!fallback_output) {
1282         MP_ERR(wl, "No screens could be found!\n");
1283         return NULL;
1284     } else if (wl->vo_opts->fsscreen_id >= 0) {
1285         MP_WARN(wl, "Screen index %i not found/unavailable! Falling back to screen 0!\n", screen_id);
1286     } else if (wl->vo_opts->fsscreen_name) {
1287         MP_WARN(wl, "Screen name %s not found/unavailable! Falling back to screen 0!\n", screen_name);
1288     }
1289     return fallback_output;
1290 }
1291 
last_available_sync(struct vo_wayland_state * wl)1292 static int last_available_sync(struct vo_wayland_state *wl)
1293 {
1294     for (int i = wl->sync_size - 1; i > -1; --i) {
1295         if (!wl->sync[i].filled)
1296             return i;
1297     }
1298     return -1;
1299 }
1300 
lookupkey(int key)1301 static int lookupkey(int key)
1302 {
1303     const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]";
1304 
1305     int mpkey = 0;
1306     if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') ||
1307         (key >= '0' && key <= '9') ||
1308         (key >  0   && key <  256 && strchr(passthrough_keys, key)))
1309         mpkey = key;
1310 
1311     if (!mpkey)
1312         mpkey = lookup_keymap_table(keymap, key);
1313 
1314     return mpkey;
1315 }
1316 
queue_new_sync(struct vo_wayland_state * wl)1317 static void queue_new_sync(struct vo_wayland_state *wl)
1318 {
1319     wl->sync_size += 1;
1320     wl->sync = talloc_realloc(wl, wl->sync, struct vo_wayland_sync, wl->sync_size);
1321     sync_shift(wl);
1322 }
1323 
request_decoration_mode(struct vo_wayland_state * wl,uint32_t mode)1324 static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode)
1325 {
1326     wl->requested_decoration = mode;
1327     zxdg_toplevel_decoration_v1_set_mode(wl->xdg_toplevel_decoration, mode);
1328 }
1329 
remove_output(struct vo_wayland_output * out)1330 static void remove_output(struct vo_wayland_output *out)
1331 {
1332     if (!out)
1333         return;
1334 
1335     MP_VERBOSE(out->wl, "Deregistering output %s %s (0x%x)\n", out->make,
1336                out->model, out->id);
1337     wl_list_remove(&out->link);
1338     talloc_free(out->make);
1339     talloc_free(out->model);
1340     talloc_free(out);
1341     return;
1342 }
1343 
set_cursor_visibility(struct vo_wayland_state * wl,bool on)1344 static int set_cursor_visibility(struct vo_wayland_state *wl, bool on)
1345 {
1346     wl->cursor_visible = on;
1347     if (on) {
1348         if (spawn_cursor(wl))
1349             return VO_FALSE;
1350         struct wl_cursor_image *img = wl->default_cursor->images[0];
1351         struct wl_buffer *buffer = wl_cursor_image_get_buffer(img);
1352         if (!buffer)
1353             return VO_FALSE;
1354         wl_pointer_set_cursor(wl->pointer, wl->pointer_id, wl->cursor_surface,
1355                               img->hotspot_x/wl->scaling, img->hotspot_y/wl->scaling);
1356         wl_surface_set_buffer_scale(wl->cursor_surface, wl->scaling);
1357         wl_surface_attach(wl->cursor_surface, buffer, 0, 0);
1358         wl_surface_damage(wl->cursor_surface, 0, 0, img->width, img->height);
1359         wl_surface_commit(wl->cursor_surface);
1360     } else {
1361         wl_pointer_set_cursor(wl->pointer, wl->pointer_id, NULL, 0, 0);
1362     }
1363     return VO_TRUE;
1364 }
1365 
set_geometry(struct vo_wayland_state * wl)1366 static void set_geometry(struct vo_wayland_state *wl)
1367 {
1368     struct vo *vo = wl->vo;
1369     assert(wl->current_output);
1370 
1371     struct vo_win_geometry geo;
1372     struct mp_rect screenrc = wl->current_output->geometry;
1373     vo_calc_window_geometry(vo, &screenrc, &geo);
1374     vo_apply_window_geometry(vo, &geo);
1375 
1376     greatest_common_divisor(wl, vo->dwidth, vo->dheight);
1377     wl->reduced_width = vo->dwidth / wl->gcd;
1378     wl->reduced_height = vo->dheight / wl->gcd;
1379 
1380     wl->vdparams.x0 = 0;
1381     wl->vdparams.y0 = 0;
1382     wl->vdparams.x1 = vo->dwidth / wl->scaling;
1383     wl->vdparams.y1 = vo->dheight / wl->scaling;
1384 }
1385 
set_screensaver_inhibitor(struct vo_wayland_state * wl,int state)1386 static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state)
1387 {
1388     if (!wl->idle_inhibit_manager)
1389         return VO_NOTIMPL;
1390     if (state == (!!wl->idle_inhibitor))
1391         return VO_TRUE;
1392     if (state) {
1393         MP_VERBOSE(wl, "Enabling idle inhibitor\n");
1394         struct zwp_idle_inhibit_manager_v1 *mgr = wl->idle_inhibit_manager;
1395         wl->idle_inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(mgr, wl->surface);
1396     } else {
1397         MP_VERBOSE(wl, "Disabling the idle inhibitor\n");
1398         zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor);
1399         wl->idle_inhibitor = NULL;
1400     }
1401     return VO_TRUE;
1402 }
1403 
set_surface_scaling(struct vo_wayland_state * wl)1404 static void set_surface_scaling(struct vo_wayland_state *wl)
1405 {
1406     int old_scale = wl->scaling;
1407     if (wl->vo_opts->hidpi_window_scale) {
1408         wl->scaling = wl->current_output->scale;
1409     } else {
1410         wl->scaling = 1;
1411     }
1412 
1413     double factor = (double)old_scale / wl->scaling;
1414     wl->vdparams.x1 *= factor;
1415     wl->vdparams.y1 *= factor;
1416     wl->window_size.x1 *= factor;
1417     wl->window_size.y1 *= factor;
1418 }
1419 
spawn_cursor(struct vo_wayland_state * wl)1420 static int spawn_cursor(struct vo_wayland_state *wl)
1421 {
1422     /* Reuse if size is identical */
1423     if (!wl->pointer || wl->allocated_cursor_scale == wl->scaling)
1424         return 0;
1425     else if (wl->cursor_theme)
1426         wl_cursor_theme_destroy(wl->cursor_theme);
1427 
1428     const char *xcursor_theme = getenv("XCURSOR_THEME");
1429     const char *size_str = getenv("XCURSOR_SIZE");
1430     int size = 24;
1431     if (size_str != NULL) {
1432         errno = 0;
1433         char *end;
1434         long size_long = strtol(size_str, &end, 10);
1435         if (!*end && !errno && size_long > 0 && size_long <= INT_MAX)
1436             size = (int)size_long;
1437     }
1438 
1439     wl->cursor_theme = wl_cursor_theme_load(xcursor_theme, size*wl->scaling, wl->shm);
1440     if (!wl->cursor_theme) {
1441         MP_ERR(wl, "Unable to load cursor theme!\n");
1442         return 1;
1443     }
1444 
1445     wl->default_cursor = wl_cursor_theme_get_cursor(wl->cursor_theme, "left_ptr");
1446     if (!wl->default_cursor) {
1447         MP_ERR(wl, "Unable to load cursor theme!\n");
1448         return 1;
1449     }
1450 
1451     wl->allocated_cursor_scale = wl->scaling;
1452 
1453     return 0;
1454 }
1455 
sync_shift(struct vo_wayland_state * wl)1456 static void sync_shift(struct vo_wayland_state *wl)
1457 {
1458     for (int i = wl->sync_size - 1; i > 0; --i) {
1459         wl->sync[i] = wl->sync[i-1];
1460     }
1461     struct vo_wayland_sync sync = {0, 0, 0, 0};
1462     wl->sync[0] = sync;
1463 }
1464 
toggle_fullscreen(struct vo_wayland_state * wl)1465 static void toggle_fullscreen(struct vo_wayland_state *wl)
1466 {
1467     if (!wl->xdg_toplevel)
1468         return;
1469     wl->state_change = true;
1470     bool specific_screen = wl->vo_opts->fsscreen_id >= 0 || wl->vo_opts->fsscreen_name;
1471     if (wl->vo_opts->fullscreen && !specific_screen) {
1472         xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
1473     } else if (wl->vo_opts->fullscreen && specific_screen) {
1474         struct vo_wayland_output *output = find_output(wl);
1475         xdg_toplevel_set_fullscreen(wl->xdg_toplevel, output->output);
1476     } else {
1477         xdg_toplevel_unset_fullscreen(wl->xdg_toplevel);
1478     }
1479 }
1480 
toggle_maximized(struct vo_wayland_state * wl)1481 static void toggle_maximized(struct vo_wayland_state *wl)
1482 {
1483     if (!wl->xdg_toplevel)
1484         return;
1485     wl->state_change = true;
1486     if (wl->vo_opts->window_maximized) {
1487         xdg_toplevel_set_maximized(wl->xdg_toplevel);
1488     } else {
1489         xdg_toplevel_unset_maximized(wl->xdg_toplevel);
1490     }
1491 }
1492 
update_app_id(struct vo_wayland_state * wl)1493 static void update_app_id(struct vo_wayland_state *wl)
1494 {
1495     if (!wl->xdg_toplevel)
1496         return;
1497     xdg_toplevel_set_app_id(wl->xdg_toplevel, wl->vo_opts->appid);
1498 }
1499 
update_window_title(struct vo_wayland_state * wl,const char * title)1500 static int update_window_title(struct vo_wayland_state *wl, const char *title)
1501 {
1502     if (!wl->xdg_toplevel)
1503         return VO_NOTAVAIL;
1504     xdg_toplevel_set_title(wl->xdg_toplevel, title);
1505     return VO_TRUE;
1506 }
1507 
window_move(struct vo_wayland_state * wl,uint32_t serial)1508 static void window_move(struct vo_wayland_state *wl, uint32_t serial)
1509 {
1510     if (wl->xdg_toplevel)
1511         xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
1512 }
1513 
vo_wayland_dispatch_events(struct vo_wayland_state * wl,int nfds,int timeout)1514 static void vo_wayland_dispatch_events(struct vo_wayland_state *wl, int nfds, int timeout)
1515 {
1516     struct pollfd fds[2] = {
1517         {.fd = wl->display_fd,     .events = POLLIN },
1518         {.fd = wl->wakeup_pipe[0], .events = POLLIN },
1519     };
1520 
1521     while (wl_display_prepare_read(wl->display) != 0)
1522         wl_display_dispatch_pending(wl->display);
1523     wl_display_flush(wl->display);
1524 
1525     poll(fds, nfds, timeout);
1526 
1527     if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1528         MP_FATAL(wl, "Error occurred on the display fd, closing\n");
1529         wl_display_cancel_read(wl->display);
1530         close(wl->display_fd);
1531         wl->display_fd = -1;
1532         mp_input_put_key(wl->vo->input_ctx, MP_KEY_CLOSE_WIN);
1533     } else {
1534         wl_display_read_events(wl->display);
1535     }
1536 
1537     if (fds[0].revents & POLLIN)
1538         wl_display_dispatch_pending(wl->display);
1539 
1540     if (fds[1].revents & POLLIN)
1541         mp_flush_wakeup_pipe(wl->wakeup_pipe[0]);
1542 }
1543 
1544 /* Non-static */
vo_wayland_control(struct vo * vo,int * events,int request,void * arg)1545 int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
1546 {
1547     struct vo_wayland_state *wl = vo->wl;
1548     struct mp_vo_opts *opts = wl->vo_opts;
1549     wl_display_dispatch_pending(wl->display);
1550 
1551     switch (request) {
1552     case VOCTRL_CHECK_EVENTS: {
1553         check_dnd_fd(wl);
1554         *events |= wl->pending_vo_events;
1555         wl->pending_vo_events = 0;
1556         return VO_TRUE;
1557     }
1558     case VOCTRL_VO_OPTS_CHANGED: {
1559         void *opt;
1560         while (m_config_cache_get_next_changed(wl->vo_opts_cache, &opt)) {
1561             if (opt == &opts->appid)
1562                 update_app_id(wl);
1563             if (opt == &opts->border)
1564             {
1565                 // This is stupid but the value of border shouldn't be written
1566                 // unless we get a configure event. Change it back to its old
1567                 // value and let configure_decorations handle it after the request.
1568                 if (wl->xdg_toplevel_decoration) {
1569                     opts->border = !opts->border;
1570                     m_config_cache_write_opt(wl->vo_opts_cache,
1571                                              &opts->border);
1572                     request_decoration_mode(wl, !opts->border + 1);
1573                 } else {
1574                     opts->border = false;
1575                     m_config_cache_write_opt(wl->vo_opts_cache,
1576                                              &wl->vo_opts->border);
1577                 }
1578             }
1579             if (opt == &opts->fullscreen)
1580                 toggle_fullscreen(wl);
1581             if (opt == &opts->hidpi_window_scale)
1582             {
1583                 set_surface_scaling(wl);
1584                 if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) {
1585                     wl_surface_set_buffer_scale(wl->surface, wl->scaling);
1586                 } else {
1587                     wl->scale_change = true;
1588                 }
1589             }
1590             if (opt == &opts->window_maximized)
1591                 toggle_maximized(wl);
1592             if (opt == &opts->window_minimized)
1593                 do_minimize(wl);
1594             if (opt == &opts->geometry || opt == &opts->autofit ||
1595                 opt == &opts->autofit_smaller || opt == &opts->autofit_larger)
1596             {
1597                 if (wl->current_output) {
1598                     set_geometry(wl);
1599                     wl->window_size = wl->vdparams;
1600                     if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized)
1601                         wl->geometry = wl->window_size;
1602                     wl->pending_vo_events |= VO_EVENT_RESIZE;
1603                 }
1604             }
1605         }
1606         return VO_TRUE;
1607     }
1608     case VOCTRL_GET_FOCUSED: {
1609         *(bool *)arg = wl->focused;
1610         return VO_TRUE;
1611     }
1612     case VOCTRL_GET_DISPLAY_NAMES: {
1613         *(char ***)arg = get_displays_spanned(wl);
1614         return VO_TRUE;
1615     }
1616     case VOCTRL_GET_UNFS_WINDOW_SIZE: {
1617         int *s = arg;
1618         if (wl->vo_opts->window_maximized) {
1619             s[0] = mp_rect_w(wl->geometry) * wl->scaling;
1620             s[1] = mp_rect_h(wl->geometry) * wl->scaling;
1621         } else {
1622             s[0] = mp_rect_w(wl->window_size) * wl->scaling;
1623             s[1] = mp_rect_h(wl->window_size) * wl->scaling;
1624         }
1625         return VO_TRUE;
1626     }
1627     case VOCTRL_SET_UNFS_WINDOW_SIZE: {
1628         int *s = arg;
1629         wl->window_size.x0 = 0;
1630         wl->window_size.y0 = 0;
1631         wl->window_size.x1 = s[0] / wl->scaling;
1632         wl->window_size.y1 = s[1] / wl->scaling;
1633         if (!wl->vo_opts->fullscreen) {
1634             if (wl->vo_opts->window_maximized) {
1635                 xdg_toplevel_unset_maximized(wl->xdg_toplevel);
1636                 wl_display_dispatch_pending(wl->display);
1637                 /* Make sure the compositor let us unmaximize */
1638                 if (wl->vo_opts->window_maximized)
1639                     return VO_TRUE;
1640             }
1641             wl->geometry = wl->window_size;
1642             wl->pending_vo_events |= VO_EVENT_RESIZE;
1643         }
1644         return VO_TRUE;
1645     }
1646     case VOCTRL_GET_DISPLAY_FPS: {
1647         if (!wl->current_output)
1648             return VO_NOTAVAIL;
1649         *(double *)arg = wl->current_output->refresh_rate;
1650         return VO_TRUE;
1651     }
1652     case VOCTRL_GET_DISPLAY_RES: {
1653         if (!wl->current_output)
1654             return VO_NOTAVAIL;
1655         ((int *)arg)[0] = wl->current_output->geometry.x1;
1656         ((int *)arg)[1] = wl->current_output->geometry.y1;
1657         return VO_TRUE;
1658     }
1659     case VOCTRL_GET_HIDPI_SCALE: {
1660         if (!wl->scaling)
1661             return VO_NOTAVAIL;
1662         *(double *)arg = wl->scaling;
1663         return VO_TRUE;
1664     }
1665     case VOCTRL_UPDATE_WINDOW_TITLE:
1666         return update_window_title(wl, (const char *)arg);
1667     case VOCTRL_SET_CURSOR_VISIBILITY:
1668         if (!wl->pointer)
1669             return VO_NOTAVAIL;
1670         return set_cursor_visibility(wl, *(bool *)arg);
1671     case VOCTRL_KILL_SCREENSAVER:
1672         return set_screensaver_inhibitor(wl, true);
1673     case VOCTRL_RESTORE_SCREENSAVER:
1674         return set_screensaver_inhibitor(wl, false);
1675     }
1676 
1677     return VO_NOTIMPL;
1678 }
1679 
vo_wayland_init(struct vo * vo)1680 int vo_wayland_init(struct vo *vo)
1681 {
1682     vo->wl = talloc_zero(NULL, struct vo_wayland_state);
1683     struct vo_wayland_state *wl = vo->wl;
1684 
1685     *wl = (struct vo_wayland_state) {
1686         .display = wl_display_connect(NULL),
1687         .vo = vo,
1688         .log = mp_log_new(wl, vo->log, "wayland"),
1689         .scaling = 1,
1690         .wakeup_pipe = {-1, -1},
1691         .dnd_fd = -1,
1692         .cursor_visible = true,
1693         .vo_opts_cache = m_config_cache_alloc(wl, vo->global, &vo_sub_opts),
1694     };
1695     wl->vo_opts = wl->vo_opts_cache->opts;
1696 
1697     wl_list_init(&wl->output_list);
1698 
1699     if (!wl->display)
1700         return false;
1701 
1702     if (create_input(wl))
1703         return false;
1704 
1705     wl->registry = wl_display_get_registry(wl->display);
1706     wl_registry_add_listener(wl->registry, &registry_listener, wl);
1707 
1708     /* Do a roundtrip to run the registry */
1709     wl_display_roundtrip(wl->display);
1710 
1711     if (!wl->wm_base) {
1712         MP_FATAL(wl, "Compositor doesn't support the required %s protocol!\n",
1713                  xdg_wm_base_interface.name);
1714         return false;
1715     }
1716 
1717     if (!wl_list_length(&wl->output_list)) {
1718         MP_FATAL(wl, "No outputs found or compositor doesn't support %s (ver. 2)\n",
1719                  wl_output_interface.name);
1720         return false;
1721     }
1722 
1723     /* Can't be initialized during registry due to multi-protocol dependence */
1724     if (create_xdg_surface(wl))
1725         return false;
1726 
1727     const char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
1728     if (xdg_current_desktop != NULL && strstr(xdg_current_desktop, "GNOME"))
1729         MP_WARN(wl, "GNOME's wayland compositor lacks support for the idle inhibit protocol. This means the screen can blank during playback.\n");
1730 
1731     if (wl->dnd_devman && wl->seat) {
1732         wl->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, wl->seat);
1733         wl_data_device_add_listener(wl->dnd_ddev, &data_device_listener, wl);
1734     } else if (!wl->dnd_devman) {
1735         MP_VERBOSE(wl, "Compositor doesn't support the %s (ver. 3) protocol!\n",
1736                    wl_data_device_manager_interface.name);
1737     }
1738 
1739     if (wl->presentation) {
1740         wl->sync = talloc_zero_array(wl, struct vo_wayland_sync, 1);
1741         struct vo_wayland_sync sync = {0, 0, 0, 0};
1742         wl->sync[0] = sync;
1743         wl->sync_size += 1;
1744     } else {
1745         MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
1746                    wp_presentation_interface.name);
1747     }
1748 
1749     if (wl->xdg_decoration_manager) {
1750         wl->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(wl->xdg_decoration_manager, wl->xdg_toplevel);
1751         zxdg_toplevel_decoration_v1_add_listener(wl->xdg_toplevel_decoration, &decoration_listener, wl);
1752         request_decoration_mode(wl, wl->vo_opts->border + 1);
1753     } else {
1754         wl->vo_opts->border = false;
1755         m_config_cache_write_opt(wl->vo_opts_cache,
1756                                  &wl->vo_opts->border);
1757         MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
1758                    zxdg_decoration_manager_v1_interface.name);
1759     }
1760 
1761     if (!wl->idle_inhibit_manager)
1762         MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
1763                    zwp_idle_inhibit_manager_v1_interface.name);
1764 
1765     wl->opts = mp_get_config_group(wl, wl->vo->global, &wayland_conf);
1766     wl->display_fd = wl_display_get_fd(wl->display);
1767     wl->frame_callback = wl_surface_frame(wl->surface);
1768     wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
1769 
1770     update_app_id(wl);
1771     mp_make_wakeup_pipe(wl->wakeup_pipe);
1772 
1773     return true;
1774 }
1775 
vo_wayland_reconfig(struct vo * vo)1776 int vo_wayland_reconfig(struct vo *vo)
1777 {
1778     struct vo_wayland_state *wl = vo->wl;
1779     bool configure = false;
1780 
1781     MP_VERBOSE(wl, "Reconfiguring!\n");
1782 
1783     if (!wl->current_output) {
1784         wl->current_output = find_output(wl);
1785         if (!wl->current_output)
1786             return false;
1787         set_surface_scaling(wl);
1788         wl_surface_set_buffer_scale(wl->surface, wl->scaling);
1789         wl_surface_commit(wl->surface);
1790         configure = true;
1791     }
1792 
1793     set_geometry(wl);
1794 
1795     wl->window_size = wl->vdparams;
1796 
1797     if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized)
1798         wl->geometry = wl->window_size;
1799 
1800     if (wl->vo_opts->fullscreen)
1801         toggle_fullscreen(wl);
1802 
1803     if (wl->vo_opts->window_maximized)
1804         toggle_maximized(wl);
1805 
1806     if (wl->vo_opts->window_minimized)
1807         do_minimize(wl);
1808 
1809     if (configure) {
1810         wl->window_size = wl->vdparams;
1811         wl->geometry = wl->window_size;
1812         wl_display_roundtrip(wl->display);
1813         wl->pending_vo_events |= VO_EVENT_DPI;
1814     }
1815 
1816     wl->pending_vo_events |= VO_EVENT_RESIZE;
1817 
1818     return true;
1819 }
1820 
vo_wayland_set_opaque_region(struct vo_wayland_state * wl,int alpha)1821 void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, int alpha)
1822 {
1823     const int32_t width = wl->scaling * mp_rect_w(wl->geometry);
1824     const int32_t height = wl->scaling * mp_rect_h(wl->geometry);
1825     if (!alpha) {
1826         struct wl_region *region = wl_compositor_create_region(wl->compositor);
1827         wl_region_add(region, 0, 0, width, height);
1828         wl_surface_set_opaque_region(wl->surface, region);
1829         wl_region_destroy(region);
1830     } else {
1831         wl_surface_set_opaque_region(wl->surface, NULL);
1832     }
1833 }
1834 
vo_wayland_sync_swap(struct vo_wayland_state * wl)1835 void vo_wayland_sync_swap(struct vo_wayland_state *wl)
1836 {
1837     int index = wl->sync_size - 1;
1838 
1839     // If these are the same, presentation feedback has not been received.
1840     // This can happen if a frame takes too long and misses vblank.
1841     // Additionally, a compositor may return an ust value of 0. In either case,
1842     // Don't attempt to use these statistics and wait until the next presentation
1843     // event arrives.
1844     if (!wl->sync[index].ust || wl->sync[index].ust == wl->last_ust) {
1845         wl->last_skipped_vsyncs = -1;
1846         wl->vsync_duration = -1;
1847         wl->last_queue_display_time = -1;
1848         return;
1849     }
1850 
1851     wl->last_skipped_vsyncs = 0;
1852 
1853     int64_t ust_passed = wl->sync[index].ust ? wl->sync[index].ust - wl->last_ust: 0;
1854     wl->last_ust = wl->sync[index].ust;
1855     int64_t msc_passed = wl->sync[index].msc ? wl->sync[index].msc - wl->last_msc: 0;
1856     wl->last_msc = wl->sync[index].msc;
1857 
1858     if (msc_passed && ust_passed)
1859         wl->vsync_duration = ust_passed / msc_passed;
1860 
1861     struct timespec ts;
1862     if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
1863         return;
1864     }
1865 
1866     uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
1867     uint64_t ust_mp_time = mp_time_us() - (now_monotonic - wl->sync[index].ust);
1868 
1869     wl->last_queue_display_time = ust_mp_time + wl->vsync_duration;
1870 }
1871 
vo_wayland_uninit(struct vo * vo)1872 void vo_wayland_uninit(struct vo *vo)
1873 {
1874     struct vo_wayland_state *wl = vo->wl;
1875     if (!wl)
1876         return;
1877 
1878     mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
1879 
1880     if (wl->compositor)
1881         wl_compositor_destroy(wl->compositor);
1882 
1883     if (wl->current_output && wl->current_output->output)
1884         wl_output_destroy(wl->current_output->output);
1885 
1886     if (wl->cursor_surface)
1887         wl_surface_destroy(wl->cursor_surface);
1888 
1889     if (wl->cursor_theme)
1890         wl_cursor_theme_destroy(wl->cursor_theme);
1891 
1892     if (wl->dnd_ddev)
1893         wl_data_device_destroy(wl->dnd_ddev);
1894 
1895     if (wl->dnd_devman)
1896         wl_data_device_manager_destroy(wl->dnd_devman);
1897 
1898     if (wl->dnd_offer)
1899         wl_data_offer_destroy(wl->dnd_offer);
1900 
1901     if (wl->feedback)
1902         wp_presentation_feedback_destroy(wl->feedback);
1903 
1904     if (wl->frame_callback)
1905         wl_callback_destroy(wl->frame_callback);
1906 
1907     if (wl->idle_inhibitor)
1908         zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor);
1909 
1910     if (wl->idle_inhibit_manager)
1911         zwp_idle_inhibit_manager_v1_destroy(wl->idle_inhibit_manager);
1912 
1913     if (wl->keyboard)
1914         wl_keyboard_destroy(wl->keyboard);
1915 
1916     if (wl->pointer)
1917         wl_pointer_destroy(wl->pointer);
1918 
1919     if (wl->presentation)
1920         wp_presentation_destroy(wl->presentation);
1921 
1922     if (wl->registry)
1923         wl_registry_destroy(wl->registry);
1924 
1925     if (wl->seat)
1926         wl_seat_destroy(wl->seat);
1927 
1928     if (wl->shm)
1929         wl_shm_destroy(wl->shm);
1930 
1931     if (wl->surface)
1932         wl_surface_destroy(wl->surface);
1933 
1934     if (wl->wm_base)
1935         xdg_wm_base_destroy(wl->wm_base);
1936 
1937     if (wl->xdg_decoration_manager)
1938         zxdg_decoration_manager_v1_destroy(wl->xdg_decoration_manager);
1939 
1940     if (wl->xdg_toplevel)
1941         xdg_toplevel_destroy(wl->xdg_toplevel);
1942 
1943     if (wl->xdg_toplevel_decoration)
1944         zxdg_toplevel_decoration_v1_destroy(wl->xdg_toplevel_decoration);
1945 
1946     if (wl->xdg_surface)
1947         xdg_surface_destroy(wl->xdg_surface);
1948 
1949     if (wl->xkb_context)
1950         xkb_context_unref(wl->xkb_context);
1951 
1952     if (wl->xkb_keymap)
1953         xkb_keymap_unref(wl->xkb_keymap);
1954 
1955     if (wl->xkb_state)
1956         xkb_state_unref(wl->xkb_state);
1957 
1958     if (wl->display) {
1959         close(wl_display_get_fd(wl->display));
1960         wl_display_disconnect(wl->display);
1961     }
1962 
1963     struct vo_wayland_output *output, *tmp;
1964     wl_list_for_each_safe(output, tmp, &wl->output_list, link)
1965         remove_output(output);
1966 
1967     talloc_free(wl->dnd_mime_type);
1968 
1969     for (int n = 0; n < 2; n++)
1970         close(wl->wakeup_pipe[n]);
1971     talloc_free(wl);
1972     vo->wl = NULL;
1973 }
1974 
vo_wayland_wait_frame(struct vo_wayland_state * wl)1975 void vo_wayland_wait_frame(struct vo_wayland_state *wl)
1976 {
1977     int64_t vblank_time = 0;
1978     /* We need some vblank interval to use for the timeout in
1979      * this function. The order of preference of values to use is:
1980      * 1. vsync duration from presentation time
1981      * 2. refresh inteval reported by presentation time
1982      * 3. refresh rate of the output reported by the compositor
1983      * 4. make up crap if vblank_time is still <= 0 (better than nothing) */
1984 
1985     if (wl->presentation)
1986         vblank_time = wl->vsync_duration;
1987 
1988     if (vblank_time <= 0 && wl->refresh_interval > 0)
1989         vblank_time = wl->refresh_interval;
1990 
1991     if (vblank_time <= 0 && wl->current_output->refresh_rate > 0)
1992         vblank_time = 1e6 / wl->current_output->refresh_rate;
1993 
1994     // Ideally you should never reach this point.
1995     if (vblank_time <= 0)
1996         vblank_time = 1e6 / 60;
1997 
1998     int64_t finish_time = mp_time_us() + vblank_time;
1999 
2000     while (wl->frame_wait && finish_time > mp_time_us()) {
2001         int poll_time = ceil((double)(finish_time - mp_time_us()) / 1000);
2002         if (poll_time < 0) {
2003             poll_time = 0;
2004         }
2005         vo_wayland_dispatch_events(wl, 1, poll_time);
2006     }
2007 
2008     /* If the compositor does not have presentation time, we cannot be sure
2009      * that this wait is accurate. Do a hacky block with wl_display_roundtrip. */
2010     if (!wl->presentation && !wl_display_get_error(wl->display))
2011         wl_display_roundtrip(wl->display);
2012 
2013     if (wl->frame_wait) {
2014         // Only consider consecutive missed callbacks.
2015         if (wl->timeout_count > 1) {
2016             wl->hidden = true;
2017             return;
2018         } else {
2019             wl->timeout_count += 1;
2020             return;
2021         }
2022     }
2023 
2024     wl->timeout_count = 0;
2025 }
2026 
vo_wayland_wait_events(struct vo * vo,int64_t until_time_us)2027 void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us)
2028 {
2029     struct vo_wayland_state *wl = vo->wl;
2030 
2031     if (wl->display_fd == -1)
2032         return;
2033 
2034     int64_t wait_us = until_time_us - mp_time_us();
2035     int timeout_ms = MPCLAMP((wait_us + 999) / 1000, 0, 10000);
2036 
2037     vo_wayland_dispatch_events(wl, 2, timeout_ms);
2038 }
2039 
vo_wayland_wakeup(struct vo * vo)2040 void vo_wayland_wakeup(struct vo *vo)
2041 {
2042     struct vo_wayland_state *wl = vo->wl;
2043     (void)write(wl->wakeup_pipe[1], &(char){0}, 1);
2044 }
2045