1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup GHOST
19  */
20 
21 #include "GHOST_SystemWayland.h"
22 #include "GHOST_Event.h"
23 #include "GHOST_EventButton.h"
24 #include "GHOST_EventCursor.h"
25 #include "GHOST_EventDragnDrop.h"
26 #include "GHOST_EventKey.h"
27 #include "GHOST_EventWheel.h"
28 #include "GHOST_TimerManager.h"
29 #include "GHOST_WindowManager.h"
30 
31 #include "GHOST_ContextEGL.h"
32 
33 #include <EGL/egl.h>
34 #include <wayland-egl.h>
35 
36 #include <algorithm>
37 #include <atomic>
38 #include <stdexcept>
39 #include <thread>
40 #include <unordered_map>
41 #include <unordered_set>
42 
43 #include <pointer-constraints-client-protocol.h>
44 #include <relative-pointer-client-protocol.h>
45 #include <wayland-cursor.h>
46 #include <xkbcommon/xkbcommon.h>
47 
48 #include <fcntl.h>
49 #include <linux/input-event-codes.h>
50 #include <sys/mman.h>
51 #include <unistd.h>
52 
53 #include <cstring>
54 
55 struct output_t {
56   struct wl_output *output;
57   int32_t width, height;
58   int transform;
59   int scale;
60   std::string make;
61   std::string model;
62 };
63 
64 struct buffer_t {
65   void *data;
66   size_t size;
67 };
68 
69 struct cursor_t {
70   bool visible;
71   struct wl_surface *surface = nullptr;
72   struct wl_buffer *buffer;
73   struct wl_cursor_image image;
74   struct buffer_t *file_buffer = nullptr;
75 };
76 
77 struct data_offer_t {
78   std::unordered_set<std::string> types;
79   uint32_t source_actions;
80   uint32_t dnd_action;
81   struct wl_data_offer *id;
82   std::atomic<bool> in_use;
83   struct {
84     int x, y;
85   } dnd;
86 };
87 
88 struct data_source_t {
89   struct wl_data_source *data_source;
90   /** Last device that was active. */
91   uint32_t source_serial;
92   char *buffer_out;
93 };
94 
95 struct key_repeat_payload_t {
96   GHOST_SystemWayland *system;
97   GHOST_IWindow *window;
98   GHOST_TKey key;
99   GHOST_TEventKeyData key_data;
100 };
101 
102 struct input_t {
103   GHOST_SystemWayland *system;
104 
105   std::string name;
106   struct wl_seat *seat;
107   struct wl_pointer *pointer = nullptr;
108   struct wl_keyboard *keyboard = nullptr;
109 
110   uint32_t pointer_serial;
111   int x, y;
112   GHOST_Buttons buttons;
113   struct cursor_t cursor;
114 
115   struct zwp_relative_pointer_v1 *relative_pointer;
116   struct zwp_locked_pointer_v1 *locked_pointer;
117 
118   struct xkb_context *xkb_context;
119   struct xkb_state *xkb_state;
120   struct {
121     /* Key repetition in character per second. */
122     int32_t rate;
123     /* Time (milliseconds) after which to start repeating keys. */
124     int32_t delay;
125     /* Timer for key repeats. */
126     GHOST_ITimerTask *timer = nullptr;
127   } key_repeat;
128 
129   struct wl_surface *focus_pointer = nullptr;
130   struct wl_surface *focus_keyboard = nullptr;
131 
132   struct wl_data_device *data_device = nullptr;
133   struct data_offer_t *data_offer_dnd;        /* Drag & Drop. */
134   struct data_offer_t *data_offer_copy_paste; /* Copy & Paste. */
135 
136   struct data_source_t *data_source;
137 };
138 
139 struct display_t {
140   GHOST_SystemWayland *system;
141 
142   struct wl_display *display;
143   struct wl_compositor *compositor = nullptr;
144   struct xdg_wm_base *xdg_shell = nullptr;
145   struct wl_shm *shm = nullptr;
146   std::vector<output_t *> outputs;
147   std::vector<input_t *> inputs;
148   struct wl_cursor_theme *cursor_theme = nullptr;
149   struct wl_data_device_manager *data_device_manager = nullptr;
150   struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
151   struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
152 
153   std::vector<struct wl_surface *> os_surfaces;
154   std::vector<struct wl_egl_window *> os_egl_windows;
155 };
156 
display_destroy(display_t * d)157 static void display_destroy(display_t *d)
158 {
159   if (d->data_device_manager) {
160     wl_data_device_manager_destroy(d->data_device_manager);
161   }
162 
163   for (output_t *output : d->outputs) {
164     wl_output_destroy(output->output);
165     delete output;
166   }
167 
168   for (input_t *input : d->inputs) {
169     if (input->data_source) {
170       free(input->data_source->buffer_out);
171       if (input->data_source->data_source) {
172         wl_data_source_destroy(input->data_source->data_source);
173       }
174       delete input->data_source;
175     }
176     if (input->data_offer_copy_paste) {
177       wl_data_offer_destroy(input->data_offer_copy_paste->id);
178       delete input->data_offer_copy_paste;
179     }
180     if (input->data_device) {
181       wl_data_device_release(input->data_device);
182     }
183     if (input->pointer) {
184       if (input->cursor.file_buffer) {
185         munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size);
186         delete input->cursor.file_buffer;
187       }
188       if (input->cursor.surface) {
189         wl_surface_destroy(input->cursor.surface);
190       }
191       if (input->pointer) {
192         wl_pointer_destroy(input->pointer);
193       }
194     }
195     if (input->keyboard) {
196       if (input->key_repeat.timer) {
197         delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
198         input->system->removeTimer(input->key_repeat.timer);
199         input->key_repeat.timer = nullptr;
200       }
201       wl_keyboard_destroy(input->keyboard);
202     }
203     if (input->xkb_state) {
204       xkb_state_unref(input->xkb_state);
205     }
206     if (input->xkb_context) {
207       xkb_context_unref(input->xkb_context);
208     }
209     wl_seat_destroy(input->seat);
210     delete input;
211   }
212 
213   if (d->cursor_theme) {
214     wl_cursor_theme_destroy(d->cursor_theme);
215   }
216 
217   if (d->shm) {
218     wl_shm_destroy(d->shm);
219   }
220 
221   if (d->relative_pointer_manager) {
222     zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
223   }
224 
225   if (d->pointer_constraints) {
226     zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
227   }
228 
229   for (wl_egl_window *os_egl_window : d->os_egl_windows) {
230     wl_egl_window_destroy(os_egl_window);
231   }
232 
233   for (wl_surface *os_surface : d->os_surfaces) {
234     wl_surface_destroy(os_surface);
235   }
236 
237   if (d->compositor) {
238     wl_compositor_destroy(d->compositor);
239   }
240 
241   if (d->xdg_shell) {
242     xdg_wm_base_destroy(d->xdg_shell);
243   }
244 
245   if (eglGetDisplay) {
246     ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
247   }
248 
249   if (d->display) {
250     wl_display_disconnect(d->display);
251   }
252 
253   delete d;
254 }
255 
xkb_map_gkey(const xkb_keysym_t & sym)256 static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
257 {
258 
259   GHOST_TKey gkey;
260   if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) {
261     gkey = GHOST_TKey(sym);
262   }
263   else if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9) {
264     gkey = GHOST_TKey(GHOST_kKeyNumpad0 + sym - XKB_KEY_KP_0);
265   }
266   else if (sym >= XKB_KEY_A && sym <= XKB_KEY_Z) {
267     gkey = GHOST_TKey(sym);
268   }
269   else if (sym >= XKB_KEY_a && sym <= XKB_KEY_z) {
270     gkey = GHOST_TKey(sym - XKB_KEY_a + XKB_KEY_A);
271   }
272   else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F24) {
273     gkey = GHOST_TKey(GHOST_kKeyF1 + sym - XKB_KEY_F1);
274   }
275   else {
276 
277 #define GXMAP(k, x, y) \
278   case x: \
279     k = y; \
280     break
281 
282     switch (sym) {
283       GXMAP(gkey, XKB_KEY_BackSpace, GHOST_kKeyBackSpace);
284       GXMAP(gkey, XKB_KEY_Tab, GHOST_kKeyTab);
285       GXMAP(gkey, XKB_KEY_Linefeed, GHOST_kKeyLinefeed);
286       GXMAP(gkey, XKB_KEY_Clear, GHOST_kKeyClear);
287       GXMAP(gkey, XKB_KEY_Return, GHOST_kKeyEnter);
288 
289       GXMAP(gkey, XKB_KEY_Escape, GHOST_kKeyEsc);
290       GXMAP(gkey, XKB_KEY_space, GHOST_kKeySpace);
291       GXMAP(gkey, XKB_KEY_apostrophe, GHOST_kKeyQuote);
292       GXMAP(gkey, XKB_KEY_comma, GHOST_kKeyComma);
293       GXMAP(gkey, XKB_KEY_minus, GHOST_kKeyMinus);
294       GXMAP(gkey, XKB_KEY_plus, GHOST_kKeyPlus);
295       GXMAP(gkey, XKB_KEY_period, GHOST_kKeyPeriod);
296       GXMAP(gkey, XKB_KEY_slash, GHOST_kKeySlash);
297 
298       GXMAP(gkey, XKB_KEY_semicolon, GHOST_kKeySemicolon);
299       GXMAP(gkey, XKB_KEY_equal, GHOST_kKeyEqual);
300 
301       GXMAP(gkey, XKB_KEY_bracketleft, GHOST_kKeyLeftBracket);
302       GXMAP(gkey, XKB_KEY_bracketright, GHOST_kKeyRightBracket);
303       GXMAP(gkey, XKB_KEY_backslash, GHOST_kKeyBackslash);
304       GXMAP(gkey, XKB_KEY_grave, GHOST_kKeyAccentGrave);
305 
306       GXMAP(gkey, XKB_KEY_Shift_L, GHOST_kKeyLeftShift);
307       GXMAP(gkey, XKB_KEY_Shift_R, GHOST_kKeyRightShift);
308       GXMAP(gkey, XKB_KEY_Control_L, GHOST_kKeyLeftControl);
309       GXMAP(gkey, XKB_KEY_Control_R, GHOST_kKeyRightControl);
310       GXMAP(gkey, XKB_KEY_Alt_L, GHOST_kKeyLeftAlt);
311       GXMAP(gkey, XKB_KEY_Alt_R, GHOST_kKeyRightAlt);
312       GXMAP(gkey, XKB_KEY_Super_L, GHOST_kKeyOS);
313       GXMAP(gkey, XKB_KEY_Super_R, GHOST_kKeyOS);
314       GXMAP(gkey, XKB_KEY_Menu, GHOST_kKeyApp);
315 
316       GXMAP(gkey, XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock);
317       GXMAP(gkey, XKB_KEY_Num_Lock, GHOST_kKeyNumLock);
318       GXMAP(gkey, XKB_KEY_Scroll_Lock, GHOST_kKeyScrollLock);
319 
320       GXMAP(gkey, XKB_KEY_Left, GHOST_kKeyLeftArrow);
321       GXMAP(gkey, XKB_KEY_Right, GHOST_kKeyRightArrow);
322       GXMAP(gkey, XKB_KEY_Up, GHOST_kKeyUpArrow);
323       GXMAP(gkey, XKB_KEY_Down, GHOST_kKeyDownArrow);
324 
325       GXMAP(gkey, XKB_KEY_Print, GHOST_kKeyPrintScreen);
326       GXMAP(gkey, XKB_KEY_Pause, GHOST_kKeyPause);
327 
328       GXMAP(gkey, XKB_KEY_Insert, GHOST_kKeyInsert);
329       GXMAP(gkey, XKB_KEY_Delete, GHOST_kKeyDelete);
330       GXMAP(gkey, XKB_KEY_Home, GHOST_kKeyHome);
331       GXMAP(gkey, XKB_KEY_End, GHOST_kKeyEnd);
332       GXMAP(gkey, XKB_KEY_Page_Up, GHOST_kKeyUpPage);
333       GXMAP(gkey, XKB_KEY_Page_Down, GHOST_kKeyDownPage);
334 
335       GXMAP(gkey, XKB_KEY_KP_Decimal, GHOST_kKeyNumpadPeriod);
336       GXMAP(gkey, XKB_KEY_KP_Enter, GHOST_kKeyNumpadEnter);
337       GXMAP(gkey, XKB_KEY_KP_Add, GHOST_kKeyNumpadPlus);
338       GXMAP(gkey, XKB_KEY_KP_Subtract, GHOST_kKeyNumpadMinus);
339       GXMAP(gkey, XKB_KEY_KP_Multiply, GHOST_kKeyNumpadAsterisk);
340       GXMAP(gkey, XKB_KEY_KP_Divide, GHOST_kKeyNumpadSlash);
341 
342       GXMAP(gkey, XKB_KEY_XF86AudioPlay, GHOST_kKeyMediaPlay);
343       GXMAP(gkey, XKB_KEY_XF86AudioStop, GHOST_kKeyMediaStop);
344       GXMAP(gkey, XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst);
345       GXMAP(gkey, XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast);
346       default:
347         GHOST_PRINT("unhandled key: " << std::hex << std::showbase << sym << std::dec << " ("
348                                       << sym << ")" << std::endl);
349         gkey = GHOST_kKeyUnknown;
350     }
351 #undef GXMAP
352   }
353 
354   return gkey;
355 }
356 
357 static const int default_cursor_size = 24;
358 
359 static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
360     {GHOST_kStandardCursorDefault, "left_ptr"},
361     {GHOST_kStandardCursorRightArrow, "right_ptr"},
362     {GHOST_kStandardCursorLeftArrow, "left_ptr"},
363     {GHOST_kStandardCursorInfo, ""},
364     {GHOST_kStandardCursorDestroy, ""},
365     {GHOST_kStandardCursorHelp, "question_arrow"},
366     {GHOST_kStandardCursorWait, "watch"},
367     {GHOST_kStandardCursorText, "xterm"},
368     {GHOST_kStandardCursorCrosshair, "crosshair"},
369     {GHOST_kStandardCursorCrosshairA, ""},
370     {GHOST_kStandardCursorCrosshairB, ""},
371     {GHOST_kStandardCursorCrosshairC, ""},
372     {GHOST_kStandardCursorPencil, ""},
373     {GHOST_kStandardCursorUpArrow, "sb_up_arrow"},
374     {GHOST_kStandardCursorDownArrow, "sb_down_arrow"},
375     {GHOST_kStandardCursorVerticalSplit, ""},
376     {GHOST_kStandardCursorHorizontalSplit, ""},
377     {GHOST_kStandardCursorEraser, ""},
378     {GHOST_kStandardCursorKnife, ""},
379     {GHOST_kStandardCursorEyedropper, ""},
380     {GHOST_kStandardCursorZoomIn, ""},
381     {GHOST_kStandardCursorZoomOut, ""},
382     {GHOST_kStandardCursorMove, "move"},
383     {GHOST_kStandardCursorNSEWScroll, ""},
384     {GHOST_kStandardCursorNSScroll, ""},
385     {GHOST_kStandardCursorEWScroll, ""},
386     {GHOST_kStandardCursorStop, ""},
387     {GHOST_kStandardCursorUpDown, "sb_v_double_arrow"},
388     {GHOST_kStandardCursorLeftRight, "sb_h_double_arrow"},
389     {GHOST_kStandardCursorTopSide, "top_side"},
390     {GHOST_kStandardCursorBottomSide, "bottom_side"},
391     {GHOST_kStandardCursorLeftSide, "left_side"},
392     {GHOST_kStandardCursorRightSide, "right_side"},
393     {GHOST_kStandardCursorTopLeftCorner, "top_left_corner"},
394     {GHOST_kStandardCursorTopRightCorner, "top_right_corner"},
395     {GHOST_kStandardCursorBottomRightCorner, "bottom_right_corner"},
396     {GHOST_kStandardCursorBottomLeftCorner, "bottom_left_corner"},
397     {GHOST_kStandardCursorCopy, "copy"},
398 };
399 
400 static constexpr const char *mime_text_plain = "text/plain";
401 static constexpr const char *mime_text_utf8 = "text/plain;charset=utf-8";
402 static constexpr const char *mime_text_uri = "text/uri-list";
403 
404 static const std::unordered_map<std::string, GHOST_TDragnDropTypes> mime_dnd = {
405     {mime_text_plain, GHOST_kDragnDropTypeString},
406     {mime_text_utf8, GHOST_kDragnDropTypeString},
407     {mime_text_uri, GHOST_kDragnDropTypeFilenames},
408 };
409 
410 static const std::vector<std::string> mime_preference_order = {
411     mime_text_uri,
412     mime_text_utf8,
413     mime_text_plain,
414 };
415 
416 static const std::vector<std::string> mime_send = {
417     "UTF8_STRING",
418     "COMPOUND_TEXT",
419     "TEXT",
420     "STRING",
421     "text/plain;charset=utf-8",
422     "text/plain",
423 };
424 
425 /* -------------------------------------------------------------------- */
426 /** \name Interface Callbacks
427  *
428  * These callbacks are registered for Wayland interfaces and called when
429  * an event is received from the compositor.
430  * \{ */
431 
relative_pointer_relative_motion(void * data,struct zwp_relative_pointer_v1 *,uint32_t,uint32_t,wl_fixed_t dx,wl_fixed_t dy,wl_fixed_t,wl_fixed_t)432 static void relative_pointer_relative_motion(
433     void *data,
434     struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
435     uint32_t /*utime_hi*/,
436     uint32_t /*utime_lo*/,
437     wl_fixed_t dx,
438     wl_fixed_t dy,
439     wl_fixed_t /*dx_unaccel*/,
440     wl_fixed_t /*dy_unaccel*/)
441 {
442   input_t *input = static_cast<input_t *>(data);
443 
444   input->x += wl_fixed_to_int(dx);
445   input->y += wl_fixed_to_int(dy);
446 
447   GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
448       wl_surface_get_user_data(input->focus_pointer));
449 
450   input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
451                                                  GHOST_kEventCursorMove,
452                                                  win,
453                                                  input->x,
454                                                  input->y,
455                                                  GHOST_TABLET_DATA_NONE));
456 }
457 
458 static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
459     relative_pointer_relative_motion,
460 };
461 
dnd_events(const input_t * const input,const GHOST_TEventType event)462 static void dnd_events(const input_t *const input, const GHOST_TEventType event)
463 {
464   const GHOST_TUns64 time = input->system->getMilliSeconds();
465   GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>(
466       wl_surface_get_user_data(input->focus_pointer));
467   for (const std::string &type : mime_preference_order) {
468     input->system->pushEvent(new GHOST_EventDragnDrop(time,
469                                                       event,
470                                                       mime_dnd.at(type),
471                                                       window,
472                                                       input->data_offer_dnd->dnd.x,
473                                                       input->data_offer_dnd->dnd.y,
474                                                       nullptr));
475   }
476 }
477 
read_pipe(data_offer_t * data_offer,const std::string mime_receive)478 static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive)
479 {
480   int pipefd[2];
481   pipe(pipefd);
482   wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]);
483   close(pipefd[1]);
484 
485   std::string data;
486   ssize_t len;
487   char buffer[4096];
488   while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
489     data.insert(data.end(), buffer, buffer + len);
490   }
491   close(pipefd[0]);
492   data_offer->in_use.store(false);
493 
494   return data;
495 }
496 
497 /**
498  * A target accepts an offered mime type.
499  *
500  * Sent when a target accepts pointer_focus or motion events. If
501  * a target does not accept any of the offered types, type is NULL.
502  */
data_source_target(void *,struct wl_data_source *,const char *)503 static void data_source_target(void * /*data*/,
504                                struct wl_data_source * /*wl_data_source*/,
505                                const char * /*mime_type*/)
506 {
507   /* pass */
508 }
509 
data_source_send(void * data,struct wl_data_source *,const char *,int32_t fd)510 static void data_source_send(void *data,
511                              struct wl_data_source * /*wl_data_source*/,
512                              const char * /*mime_type*/,
513                              int32_t fd)
514 {
515   const char *const buffer = static_cast<char *>(data);
516   write(fd, buffer, strlen(buffer) + 1);
517   close(fd);
518 }
519 
data_source_cancelled(void *,struct wl_data_source * wl_data_source)520 static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
521 {
522   wl_data_source_destroy(wl_data_source);
523 }
524 
525 /**
526  * The drag-and-drop operation physically finished.
527  *
528  * The user performed the drop action. This event does not
529  * indicate acceptance, #wl_data_source.cancelled may still be
530  * emitted afterwards if the drop destination does not accept any mime type.
531  */
data_source_dnd_drop_performed(void *,struct wl_data_source *)532 static void data_source_dnd_drop_performed(void * /*data*/,
533                                            struct wl_data_source * /*wl_data_source*/)
534 {
535   /* pass */
536 }
537 
538 /**
539  * The drag-and-drop operation concluded.
540  *
541  * The drop destination finished interoperating with this data
542  * source, so the client is now free to destroy this data source
543  * and free all associated data.
544  */
data_source_dnd_finished(void *,struct wl_data_source *)545 static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/)
546 {
547   /* pass */
548 }
549 
550 /**
551  * Notify the selected action.
552  *
553  * This event indicates the action selected by the compositor
554  * after matching the source/destination side actions. Only one
555  * action (or none) will be offered here.
556  */
data_source_action(void *,struct wl_data_source *,uint32_t)557 static void data_source_action(void * /*data*/,
558                                struct wl_data_source * /*wl_data_source*/,
559                                uint32_t /*dnd_action*/)
560 {
561   /* pass */
562 }
563 
564 static const struct wl_data_source_listener data_source_listener = {
565     data_source_target,
566     data_source_send,
567     data_source_cancelled,
568     data_source_dnd_drop_performed,
569     data_source_dnd_finished,
570     data_source_action,
571 };
572 
data_offer_offer(void * data,struct wl_data_offer *,const char * mime_type)573 static void data_offer_offer(void *data,
574                              struct wl_data_offer * /*wl_data_offer*/,
575                              const char *mime_type)
576 {
577   static_cast<data_offer_t *>(data)->types.insert(mime_type);
578 }
579 
data_offer_source_actions(void * data,struct wl_data_offer *,uint32_t source_actions)580 static void data_offer_source_actions(void *data,
581                                       struct wl_data_offer * /*wl_data_offer*/,
582                                       uint32_t source_actions)
583 {
584   static_cast<data_offer_t *>(data)->source_actions = source_actions;
585 }
586 
data_offer_action(void * data,struct wl_data_offer *,uint32_t dnd_action)587 static void data_offer_action(void *data,
588                               struct wl_data_offer * /*wl_data_offer*/,
589                               uint32_t dnd_action)
590 {
591   static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
592 }
593 
594 static const struct wl_data_offer_listener data_offer_listener = {
595     data_offer_offer,
596     data_offer_source_actions,
597     data_offer_action,
598 };
599 
data_device_data_offer(void *,struct wl_data_device *,struct wl_data_offer * id)600 static void data_device_data_offer(void * /*data*/,
601                                    struct wl_data_device * /*wl_data_device*/,
602                                    struct wl_data_offer *id)
603 {
604   data_offer_t *data_offer = new data_offer_t;
605   data_offer->id = id;
606   wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
607 }
608 
data_device_enter(void * data,struct wl_data_device *,uint32_t serial,struct wl_surface *,wl_fixed_t x,wl_fixed_t y,struct wl_data_offer * id)609 static void data_device_enter(void *data,
610                               struct wl_data_device * /*wl_data_device*/,
611                               uint32_t serial,
612                               struct wl_surface * /*surface*/,
613                               wl_fixed_t x,
614                               wl_fixed_t y,
615                               struct wl_data_offer *id)
616 {
617   input_t *input = static_cast<input_t *>(data);
618   input->data_offer_dnd = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
619   data_offer_t *data_offer = input->data_offer_dnd;
620 
621   data_offer->in_use.store(true);
622   data_offer->dnd.x = wl_fixed_to_int(x);
623   data_offer->dnd.y = wl_fixed_to_int(y);
624 
625   wl_data_offer_set_actions(id,
626                             WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
627                                 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
628                             WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
629 
630   for (const std::string &type : mime_preference_order) {
631     wl_data_offer_accept(id, serial, type.c_str());
632   }
633 
634   dnd_events(input, GHOST_kEventDraggingEntered);
635 }
636 
data_device_leave(void * data,struct wl_data_device *)637 static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/)
638 {
639   input_t *input = static_cast<input_t *>(data);
640 
641   dnd_events(input, GHOST_kEventDraggingExited);
642 
643   if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) {
644     wl_data_offer_destroy(input->data_offer_dnd->id);
645     delete input->data_offer_dnd;
646     input->data_offer_dnd = nullptr;
647   }
648 }
649 
data_device_motion(void * data,struct wl_data_device *,uint32_t,wl_fixed_t x,wl_fixed_t y)650 static void data_device_motion(void *data,
651                                struct wl_data_device * /*wl_data_device*/,
652                                uint32_t /*time*/,
653                                wl_fixed_t x,
654                                wl_fixed_t y)
655 {
656   input_t *input = static_cast<input_t *>(data);
657   input->data_offer_dnd->dnd.x = wl_fixed_to_int(x);
658   input->data_offer_dnd->dnd.y = wl_fixed_to_int(y);
659   dnd_events(input, GHOST_kEventDraggingUpdated);
660 }
661 
data_device_drop(void * data,struct wl_data_device *)662 static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/)
663 {
664   input_t *input = static_cast<input_t *>(data);
665   data_offer_t *data_offer = input->data_offer_dnd;
666 
667   const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(),
668                                                        mime_preference_order.end(),
669                                                        data_offer->types.begin(),
670                                                        data_offer->types.end());
671 
672   auto read_uris = [](input_t *const input,
673                       data_offer_t *data_offer,
674                       const std::string mime_receive) {
675     const int x = data_offer->dnd.x;
676     const int y = data_offer->dnd.y;
677 
678     const std::string data = read_pipe(data_offer, mime_receive);
679 
680     wl_data_offer_finish(data_offer->id);
681     wl_data_offer_destroy(data_offer->id);
682 
683     delete data_offer;
684     data_offer = nullptr;
685 
686     GHOST_SystemWayland *const system = input->system;
687 
688     if (mime_receive == mime_text_uri) {
689       static constexpr const char *file_proto = "file://";
690       static constexpr const char *crlf = "\r\n";
691 
692       std::vector<std::string> uris;
693 
694       size_t pos = 0;
695       while (true) {
696         pos = data.find(file_proto, pos);
697         const size_t start = pos + sizeof(file_proto) - 1;
698         pos = data.find(crlf, pos);
699         const size_t end = pos;
700 
701         if (pos == std::string::npos) {
702           break;
703         }
704         uris.push_back(data.substr(start, end - start));
705       }
706 
707       GHOST_TStringArray *flist = static_cast<GHOST_TStringArray *>(
708           malloc(sizeof(GHOST_TStringArray)));
709       flist->count = int(uris.size());
710       flist->strings = static_cast<GHOST_TUns8 **>(malloc(uris.size() * sizeof(GHOST_TUns8 *)));
711       for (size_t i = 0; i < uris.size(); i++) {
712         flist->strings[i] = static_cast<GHOST_TUns8 *>(
713             malloc((uris[i].size() + 1) * sizeof(GHOST_TUns8)));
714         memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
715       }
716       GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
717           wl_surface_get_user_data(input->focus_pointer));
718       system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
719                                                  GHOST_kEventDraggingDropDone,
720                                                  GHOST_kDragnDropTypeFilenames,
721                                                  win,
722                                                  x,
723                                                  y,
724                                                  flist));
725     }
726     else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) {
727       /* TODO: enable use of internal functions 'txt_insert_buf' and
728        * 'text_update_edited' to behave like dropped text was pasted. */
729     }
730     wl_display_roundtrip(system->display());
731   };
732 
733   std::thread read_thread(read_uris, input, data_offer, mime_receive);
734   read_thread.detach();
735 }
736 
data_device_selection(void * data,struct wl_data_device *,struct wl_data_offer * id)737 static void data_device_selection(void *data,
738                                   struct wl_data_device * /*wl_data_device*/,
739                                   struct wl_data_offer *id)
740 {
741   input_t *input = static_cast<input_t *>(data);
742   data_offer_t *data_offer = input->data_offer_copy_paste;
743 
744   /* Delete old data offer. */
745   if (data_offer != nullptr) {
746     wl_data_offer_destroy(data_offer->id);
747     delete data_offer;
748     data_offer = nullptr;
749   }
750 
751   if (id == nullptr) {
752     return;
753   }
754 
755   /* Get new data offer. */
756   data_offer = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
757   input->data_offer_copy_paste = data_offer;
758 
759   std::string mime_receive;
760   for (const std::string &type : {mime_text_utf8, mime_text_plain}) {
761     if (data_offer->types.count(type)) {
762       mime_receive = type;
763       break;
764     }
765   }
766 
767   auto read_selection = [](GHOST_SystemWayland *const system,
768                            data_offer_t *data_offer,
769                            const std::string mime_receive) {
770     const std::string data = read_pipe(data_offer, mime_receive);
771     system->setSelection(data);
772   };
773 
774   std::thread read_thread(read_selection, input->system, data_offer, mime_receive);
775   read_thread.detach();
776 }
777 
778 static const struct wl_data_device_listener data_device_listener = {
779     data_device_data_offer,
780     data_device_enter,
781     data_device_leave,
782     data_device_motion,
783     data_device_drop,
784     data_device_selection,
785 };
786 
cursor_buffer_release(void * data,struct wl_buffer * wl_buffer)787 static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer)
788 {
789   cursor_t *cursor = static_cast<cursor_t *>(data);
790 
791   wl_buffer_destroy(wl_buffer);
792   cursor->buffer = nullptr;
793 }
794 
795 const struct wl_buffer_listener cursor_buffer_listener = {
796     cursor_buffer_release,
797 };
798 
pointer_enter(void * data,struct wl_pointer *,uint32_t serial,struct wl_surface * surface,wl_fixed_t surface_x,wl_fixed_t surface_y)799 static void pointer_enter(void *data,
800                           struct wl_pointer * /*wl_pointer*/,
801                           uint32_t serial,
802                           struct wl_surface *surface,
803                           wl_fixed_t surface_x,
804                           wl_fixed_t surface_y)
805 {
806   if (!surface) {
807     return;
808   }
809   input_t *input = static_cast<input_t *>(data);
810   input->pointer_serial = serial;
811   input->x = wl_fixed_to_int(surface_x);
812   input->y = wl_fixed_to_int(surface_y);
813   input->focus_pointer = surface;
814 
815   input->system->pushEvent(
816       new GHOST_EventCursor(input->system->getMilliSeconds(),
817                             GHOST_kEventCursorMove,
818                             static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)),
819                             input->x,
820                             input->y,
821                             GHOST_TABLET_DATA_NONE));
822 }
823 
pointer_leave(void * data,struct wl_pointer *,uint32_t,struct wl_surface * surface)824 static void pointer_leave(void *data,
825                           struct wl_pointer * /*wl_pointer*/,
826                           uint32_t /*serial*/,
827                           struct wl_surface *surface)
828 {
829   if (surface != nullptr) {
830     static_cast<input_t *>(data)->focus_pointer = nullptr;
831   }
832 }
833 
pointer_motion(void * data,struct wl_pointer *,uint32_t,wl_fixed_t surface_x,wl_fixed_t surface_y)834 static void pointer_motion(void *data,
835                            struct wl_pointer * /*wl_pointer*/,
836                            uint32_t /*time*/,
837                            wl_fixed_t surface_x,
838                            wl_fixed_t surface_y)
839 {
840   input_t *input = static_cast<input_t *>(data);
841 
842   GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
843       wl_surface_get_user_data(input->focus_pointer));
844 
845   if (!win) {
846     return;
847   }
848 
849   input->x = wl_fixed_to_int(surface_x);
850   input->y = wl_fixed_to_int(surface_y);
851 
852   input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
853                                                  GHOST_kEventCursorMove,
854                                                  win,
855                                                  wl_fixed_to_int(surface_x),
856                                                  wl_fixed_to_int(surface_y),
857                                                  GHOST_TABLET_DATA_NONE));
858 }
859 
pointer_button(void * data,struct wl_pointer *,uint32_t serial,uint32_t,uint32_t button,uint32_t state)860 static void pointer_button(void *data,
861                            struct wl_pointer * /*wl_pointer*/,
862                            uint32_t serial,
863                            uint32_t /*time*/,
864                            uint32_t button,
865                            uint32_t state)
866 {
867   GHOST_TEventType etype = GHOST_kEventUnknown;
868   switch (state) {
869     case WL_POINTER_BUTTON_STATE_RELEASED:
870       etype = GHOST_kEventButtonUp;
871       break;
872     case WL_POINTER_BUTTON_STATE_PRESSED:
873       etype = GHOST_kEventButtonDown;
874       break;
875   }
876 
877   GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
878   switch (button) {
879     case BTN_LEFT:
880       ebutton = GHOST_kButtonMaskLeft;
881       break;
882     case BTN_MIDDLE:
883       ebutton = GHOST_kButtonMaskMiddle;
884       break;
885     case BTN_RIGHT:
886       ebutton = GHOST_kButtonMaskRight;
887       break;
888   }
889 
890   input_t *input = static_cast<input_t *>(data);
891   GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
892       wl_surface_get_user_data(input->focus_pointer));
893   input->data_source->source_serial = serial;
894   input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
895   input->system->pushEvent(new GHOST_EventButton(
896       input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
897 }
898 
pointer_axis(void * data,struct wl_pointer *,uint32_t,uint32_t axis,wl_fixed_t value)899 static void pointer_axis(void *data,
900                          struct wl_pointer * /*wl_pointer*/,
901                          uint32_t /*time*/,
902                          uint32_t axis,
903                          wl_fixed_t value)
904 {
905   if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
906     return;
907   }
908   input_t *input = static_cast<input_t *>(data);
909   GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
910       wl_surface_get_user_data(input->focus_pointer));
911   input->system->pushEvent(
912       new GHOST_EventWheel(input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1));
913 }
914 
915 static const struct wl_pointer_listener pointer_listener = {
916     pointer_enter,
917     pointer_leave,
918     pointer_motion,
919     pointer_button,
920     pointer_axis,
921 };
922 
keyboard_keymap(void * data,struct wl_keyboard *,uint32_t format,int32_t fd,uint32_t size)923 static void keyboard_keymap(
924     void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
925 {
926   input_t *input = static_cast<input_t *>(data);
927 
928   if ((!data) || (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)) {
929     close(fd);
930     return;
931   }
932 
933   char *map_str = static_cast<char *>(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0));
934   if (map_str == MAP_FAILED) {
935     close(fd);
936     throw std::runtime_error("keymap mmap failed: " + std::string(std::strerror(errno)));
937   }
938 
939   struct xkb_keymap *keymap = xkb_keymap_new_from_string(
940       input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
941   munmap(map_str, size);
942   close(fd);
943 
944   if (!keymap) {
945     return;
946   }
947 
948   input->xkb_state = xkb_state_new(keymap);
949 
950   xkb_keymap_unref(keymap);
951 }
952 
953 /**
954  * Enter event.
955  *
956  * Notification that this seat's keyboard focus is on a certain
957  * surface.
958  */
keyboard_enter(void * data,struct wl_keyboard *,uint32_t,struct wl_surface * surface,struct wl_array *)959 static void keyboard_enter(void *data,
960                            struct wl_keyboard * /*wl_keyboard*/,
961                            uint32_t /*serial*/,
962                            struct wl_surface *surface,
963                            struct wl_array * /*keys*/)
964 {
965   if (surface != nullptr) {
966     static_cast<input_t *>(data)->focus_keyboard = surface;
967   }
968 }
969 
970 /**
971  * Leave event.
972  *
973  * Notification that this seat's keyboard focus is no longer on a
974  * certain surface.
975  */
keyboard_leave(void * data,struct wl_keyboard *,uint32_t,struct wl_surface * surface)976 static void keyboard_leave(void *data,
977                            struct wl_keyboard * /*wl_keyboard*/,
978                            uint32_t /*serial*/,
979                            struct wl_surface *surface)
980 {
981   if (surface != nullptr) {
982     static_cast<input_t *>(data)->focus_keyboard = nullptr;
983   }
984 }
985 
986 /**
987  * A version of #xkb_state_key_get_one_sym which returns the key without any modifiers pressed.
988  * Needed because #GHOST_TKey uses these values as key-codes.
989  */
xkb_state_key_get_one_sym_without_modifiers(struct xkb_state * xkb_state,xkb_keycode_t key)990 static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(struct xkb_state *xkb_state,
991                                                                 xkb_keycode_t key)
992 {
993   /* Use an empty keyboard state to access key symbol without modifiers. */
994   xkb_state_get_keymap(xkb_state);
995   struct xkb_keymap *keymap = xkb_state_get_keymap(xkb_state);
996   struct xkb_state *xkb_state_empty = xkb_state_new(keymap);
997 
998   /* Enable number-lock. */
999   {
1000     const xkb_mod_index_t mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
1001     const xkb_mod_index_t num = xkb_keymap_mod_get_index(keymap, "NumLock");
1002     if (num != XKB_MOD_INVALID && mod2 != XKB_MOD_INVALID) {
1003       xkb_state_update_mask(xkb_state_empty, (1 << mod2), 0, (1 << num), 0, 0, 0);
1004     }
1005   }
1006 
1007   const xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state_empty, key);
1008   xkb_state_unref(xkb_state_empty);
1009   return sym;
1010 }
1011 
keyboard_key(void * data,struct wl_keyboard *,uint32_t serial,uint32_t,uint32_t key,uint32_t state)1012 static void keyboard_key(void *data,
1013                          struct wl_keyboard * /*wl_keyboard*/,
1014                          uint32_t serial,
1015                          uint32_t /*time*/,
1016                          uint32_t key,
1017                          uint32_t state)
1018 {
1019   input_t *input = static_cast<input_t *>(data);
1020 
1021   GHOST_TEventType etype = GHOST_kEventUnknown;
1022   switch (state) {
1023     case WL_KEYBOARD_KEY_STATE_RELEASED:
1024       etype = GHOST_kEventKeyUp;
1025       break;
1026     case WL_KEYBOARD_KEY_STATE_PRESSED:
1027       etype = GHOST_kEventKeyDown;
1028       break;
1029   }
1030 
1031   const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers(input->xkb_state, key + 8);
1032 
1033   if (sym == XKB_KEY_NoSymbol) {
1034     return;
1035   }
1036   const GHOST_TKey gkey = xkb_map_gkey(sym);
1037 
1038   /* Delete previous timer. */
1039   if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
1040       input->key_repeat.timer) {
1041     delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
1042     input->system->removeTimer(input->key_repeat.timer);
1043     input->key_repeat.timer = nullptr;
1044   }
1045 
1046   GHOST_TEventKeyData key_data;
1047 
1048   if (etype == GHOST_kEventKeyDown) {
1049     xkb_state_key_get_utf8(
1050         input->xkb_state, key + 8, key_data.utf8_buf, sizeof(GHOST_TEventKeyData::utf8_buf));
1051   }
1052   else {
1053     key_data.utf8_buf[0] = '\0';
1054   }
1055 
1056   input->data_source->source_serial = serial;
1057 
1058   GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
1059       wl_surface_get_user_data(input->focus_keyboard));
1060   input->system->pushEvent(new GHOST_EventKey(
1061       input->system->getMilliSeconds(), etype, win, gkey, '\0', key_data.utf8_buf, false));
1062 
1063   /* Start timer for repeating key, if applicable. */
1064   if (input->key_repeat.rate > 0 &&
1065       xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
1066       etype == GHOST_kEventKeyDown) {
1067 
1068     key_repeat_payload_t *payload = new key_repeat_payload_t({
1069         .system = input->system,
1070         .window = win,
1071         .key = gkey,
1072         .key_data = key_data,
1073     });
1074 
1075     auto cb = [](GHOST_ITimerTask *task, GHOST_TUns64 /*time*/) {
1076       struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>(
1077           task->getUserData());
1078       payload->system->pushEvent(new GHOST_EventKey(payload->system->getMilliSeconds(),
1079                                                     GHOST_kEventKeyDown,
1080                                                     payload->window,
1081                                                     payload->key,
1082                                                     '\0',
1083                                                     payload->key_data.utf8_buf,
1084                                                     true));
1085     };
1086     input->key_repeat.timer = input->system->installTimer(
1087         input->key_repeat.delay, 1000 / input->key_repeat.rate, cb, payload);
1088   }
1089 }
1090 
keyboard_modifiers(void * data,struct wl_keyboard *,uint32_t,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)1091 static void keyboard_modifiers(void *data,
1092                                struct wl_keyboard * /*wl_keyboard*/,
1093                                uint32_t /*serial*/,
1094                                uint32_t mods_depressed,
1095                                uint32_t mods_latched,
1096                                uint32_t mods_locked,
1097                                uint32_t group)
1098 {
1099   xkb_state_update_mask(static_cast<input_t *>(data)->xkb_state,
1100                         mods_depressed,
1101                         mods_latched,
1102                         mods_locked,
1103                         0,
1104                         0,
1105                         group);
1106 }
1107 
keyboard_repeat_info(void * data,struct wl_keyboard *,int32_t rate,int32_t delay)1108 static void keyboard_repeat_info(void *data,
1109                                  struct wl_keyboard * /*wl_keyboard*/,
1110                                  int32_t rate,
1111                                  int32_t delay)
1112 {
1113   input_t *input = static_cast<input_t *>(data);
1114 
1115   input->key_repeat.rate = rate;
1116   input->key_repeat.delay = delay;
1117 }
1118 
1119 static const struct wl_keyboard_listener keyboard_listener = {
1120     keyboard_keymap,
1121     keyboard_enter,
1122     keyboard_leave,
1123     keyboard_key,
1124     keyboard_modifiers,
1125     keyboard_repeat_info,
1126 };
1127 
seat_capabilities(void * data,struct wl_seat * wl_seat,uint32_t capabilities)1128 static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
1129 {
1130   input_t *input = static_cast<input_t *>(data);
1131   input->pointer = nullptr;
1132   input->keyboard = nullptr;
1133 
1134   if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
1135     input->pointer = wl_seat_get_pointer(wl_seat);
1136     input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
1137     input->cursor.visible = true;
1138     input->cursor.buffer = nullptr;
1139     input->cursor.file_buffer = new buffer_t;
1140     wl_pointer_add_listener(input->pointer, &pointer_listener, data);
1141   }
1142 
1143   if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
1144     input->keyboard = wl_seat_get_keyboard(wl_seat);
1145     wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
1146   }
1147 }
1148 
seat_name(void * data,struct wl_seat *,const char * name)1149 static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
1150 {
1151   static_cast<input_t *>(data)->name = std::string(name);
1152 }
1153 
1154 static const struct wl_seat_listener seat_listener = {
1155     seat_capabilities,
1156     seat_name,
1157 };
1158 
output_geometry(void * data,struct wl_output *,int32_t,int32_t,int32_t,int32_t,int32_t,const char * make,const char * model,int32_t transform)1159 static void output_geometry(void *data,
1160                             struct wl_output * /*wl_output*/,
1161                             int32_t /*x*/,
1162                             int32_t /*y*/,
1163                             int32_t /*physical_width*/,
1164                             int32_t /*physical_height*/,
1165                             int32_t /*subpixel*/,
1166                             const char *make,
1167                             const char *model,
1168                             int32_t transform)
1169 {
1170   output_t *output = static_cast<output_t *>(data);
1171   output->transform = transform;
1172   output->make = std::string(make);
1173   output->model = std::string(model);
1174 }
1175 
output_mode(void * data,struct wl_output *,uint32_t,int32_t width,int32_t height,int32_t)1176 static void output_mode(void *data,
1177                         struct wl_output * /*wl_output*/,
1178                         uint32_t /*flags*/,
1179                         int32_t width,
1180                         int32_t height,
1181                         int32_t /*refresh*/)
1182 {
1183   output_t *output = static_cast<output_t *>(data);
1184   output->width = width;
1185   output->height = height;
1186 }
1187 
1188 /**
1189  * Sent all information about output.
1190  *
1191  * This event is sent after all other properties have been sent
1192  * after binding to the output object and after any other property
1193  * changes done after that. This allows changes to the output
1194  * properties to be seen as atomic, even if they happen via multiple events.
1195  */
output_done(void *,struct wl_output *)1196 static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
1197 {
1198 }
1199 
output_scale(void * data,struct wl_output *,int32_t factor)1200 static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
1201 {
1202   static_cast<output_t *>(data)->scale = factor;
1203 }
1204 
1205 static const struct wl_output_listener output_listener = {
1206     output_geometry,
1207     output_mode,
1208     output_done,
1209     output_scale,
1210 };
1211 
shell_ping(void *,struct xdg_wm_base * xdg_wm_base,uint32_t serial)1212 static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
1213 {
1214   xdg_wm_base_pong(xdg_wm_base, serial);
1215 }
1216 
1217 static const struct xdg_wm_base_listener shell_listener = {
1218     shell_ping,
1219 };
1220 
global_add(void * data,struct wl_registry * wl_registry,uint32_t name,const char * interface,uint32_t)1221 static void global_add(void *data,
1222                        struct wl_registry *wl_registry,
1223                        uint32_t name,
1224                        const char *interface,
1225                        uint32_t /*version*/)
1226 {
1227   struct display_t *display = static_cast<struct display_t *>(data);
1228   if (!strcmp(interface, wl_compositor_interface.name)) {
1229     display->compositor = static_cast<wl_compositor *>(
1230         wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1));
1231   }
1232   else if (!strcmp(interface, xdg_wm_base_interface.name)) {
1233     display->xdg_shell = static_cast<xdg_wm_base *>(
1234         wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1));
1235     xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr);
1236   }
1237   else if (!strcmp(interface, wl_output_interface.name)) {
1238     output_t *output = new output_t;
1239     output->scale = 1;
1240     output->output = static_cast<wl_output *>(
1241         wl_registry_bind(wl_registry, name, &wl_output_interface, 2));
1242     display->outputs.push_back(output);
1243     wl_output_add_listener(output->output, &output_listener, output);
1244   }
1245   else if (!strcmp(interface, wl_seat_interface.name)) {
1246     input_t *input = new input_t;
1247     input->system = display->system;
1248     input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1249     input->xkb_state = nullptr;
1250     input->data_offer_dnd = nullptr;
1251     input->data_offer_copy_paste = nullptr;
1252     input->data_source = new data_source_t;
1253     input->data_source->data_source = nullptr;
1254     input->data_source->buffer_out = nullptr;
1255     input->relative_pointer = nullptr;
1256     input->locked_pointer = nullptr;
1257     input->seat = static_cast<wl_seat *>(
1258         wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
1259     display->inputs.push_back(input);
1260     wl_seat_add_listener(input->seat, &seat_listener, input);
1261   }
1262   else if (!strcmp(interface, wl_shm_interface.name)) {
1263     display->shm = static_cast<wl_shm *>(
1264         wl_registry_bind(wl_registry, name, &wl_shm_interface, 1));
1265   }
1266   else if (!strcmp(interface, wl_data_device_manager_interface.name)) {
1267     display->data_device_manager = static_cast<wl_data_device_manager *>(
1268         wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1));
1269   }
1270   else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) {
1271     display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
1272         wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1));
1273   }
1274   else if (!strcmp(interface, zwp_pointer_constraints_v1_interface.name)) {
1275     display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(
1276         wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1));
1277   }
1278 }
1279 
1280 /**
1281  * Announce removal of global object.
1282  *
1283  * Notify the client of removed global objects.
1284  *
1285  * This event notifies the client that the global identified by
1286  * name is no longer available. If the client bound to the global
1287  * using the bind request, the client should now destroy that object.
1288  */
global_remove(void *,struct wl_registry *,uint32_t)1289 static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/)
1290 {
1291 }
1292 
1293 static const struct wl_registry_listener registry_listener = {
1294     global_add,
1295     global_remove,
1296 };
1297 
1298 /** \} */
1299 
1300 /* -------------------------------------------------------------------- */
1301 /** \name Ghost Implementation
1302  *
1303  * Wayland specific implementation of the GHOST_System interface.
1304  * \{ */
1305 
GHOST_SystemWayland()1306 GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
1307 {
1308   d->system = this;
1309   /* Connect to the Wayland server. */
1310   d->display = wl_display_connect(nullptr);
1311   if (!d->display) {
1312     display_destroy(d);
1313     throw std::runtime_error("Wayland: unable to connect to display!");
1314   }
1315 
1316   /* Register interfaces. */
1317   struct wl_registry *registry = wl_display_get_registry(d->display);
1318   wl_registry_add_listener(registry, &registry_listener, d);
1319   /* Call callback for registry listener. */
1320   wl_display_roundtrip(d->display);
1321   /* Call callbacks for registered listeners. */
1322   wl_display_roundtrip(d->display);
1323   wl_registry_destroy(registry);
1324 
1325   if (!d->xdg_shell) {
1326     display_destroy(d);
1327     throw std::runtime_error("Wayland: unable to access xdg_shell!");
1328   }
1329 
1330   /* Register data device per seat for IPC between Wayland clients. */
1331   if (d->data_device_manager) {
1332     for (input_t *input : d->inputs) {
1333       input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager,
1334                                                                   input->seat);
1335       wl_data_device_add_listener(input->data_device, &data_device_listener, input);
1336     }
1337   }
1338 
1339   const char *theme = std::getenv("XCURSOR_THEME");
1340   const char *size = std::getenv("XCURSOR_SIZE");
1341   const int sizei = size ? std::stoi(size) : default_cursor_size;
1342 
1343   d->cursor_theme = wl_cursor_theme_load(theme, sizei, d->shm);
1344   if (!d->cursor_theme) {
1345     display_destroy(d);
1346     throw std::runtime_error("Wayland: unable to access cursor themes!");
1347   }
1348 }
1349 
~GHOST_SystemWayland()1350 GHOST_SystemWayland::~GHOST_SystemWayland()
1351 {
1352   display_destroy(d);
1353 }
1354 
processEvents(bool waitForEvent)1355 bool GHOST_SystemWayland::processEvents(bool waitForEvent)
1356 {
1357   const bool fired = getTimerManager()->fireTimers(getMilliSeconds());
1358 
1359   if (waitForEvent) {
1360     wl_display_dispatch(d->display);
1361   }
1362   else {
1363     wl_display_roundtrip(d->display);
1364   }
1365 
1366   return fired || (getEventManager()->getNumEvents() > 0);
1367 }
1368 
toggleConsole(int)1369 int GHOST_SystemWayland::toggleConsole(int /*action*/)
1370 {
1371   return 0;
1372 }
1373 
getModifierKeys(GHOST_ModifierKeys & keys) const1374 GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
1375 {
1376   if (!d->inputs.empty()) {
1377     static const xkb_state_component mods_all = xkb_state_component(
1378         XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
1379         XKB_STATE_MODS_EFFECTIVE);
1380 
1381     keys.set(GHOST_kModifierKeyLeftShift,
1382              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
1383                  1);
1384     keys.set(GHOST_kModifierKeyRightShift,
1385              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
1386                  1);
1387     keys.set(GHOST_kModifierKeyLeftAlt,
1388              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LAlt", mods_all) == 1);
1389     keys.set(GHOST_kModifierKeyRightAlt,
1390              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RAlt", mods_all) == 1);
1391     keys.set(GHOST_kModifierKeyLeftControl,
1392              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LControl", mods_all) == 1);
1393     keys.set(GHOST_kModifierKeyRightControl,
1394              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RControl", mods_all) == 1);
1395     keys.set(GHOST_kModifierKeyOS,
1396              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "Super", mods_all) == 1);
1397     keys.set(GHOST_kModifierKeyNumMasks,
1398              xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "NumLock", mods_all) == 1);
1399 
1400     return GHOST_kSuccess;
1401   }
1402   return GHOST_kFailure;
1403 }
1404 
getButtons(GHOST_Buttons & buttons) const1405 GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
1406 {
1407   if (!d->inputs.empty()) {
1408     buttons = d->inputs[0]->buttons;
1409     return GHOST_kSuccess;
1410   }
1411   return GHOST_kFailure;
1412 }
1413 
getClipboard(bool) const1414 GHOST_TUns8 *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
1415 {
1416   GHOST_TUns8 *clipboard = static_cast<GHOST_TUns8 *>(malloc((selection.size() + 1)));
1417   memcpy(clipboard, selection.data(), selection.size() + 1);
1418   return clipboard;
1419 }
1420 
putClipboard(GHOST_TInt8 * buffer,bool) const1421 void GHOST_SystemWayland::putClipboard(GHOST_TInt8 *buffer, bool /*selection*/) const
1422 {
1423   if (!d->data_device_manager || d->inputs.empty()) {
1424     return;
1425   }
1426 
1427   data_source_t *data_source = d->inputs[0]->data_source;
1428 
1429   /* Copy buffer. */
1430   data_source->buffer_out = static_cast<char *>(malloc(strlen(buffer) + 1));
1431   std::strcpy(data_source->buffer_out, buffer);
1432 
1433   data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager);
1434 
1435   wl_data_source_add_listener(
1436       data_source->data_source, &data_source_listener, data_source->buffer_out);
1437 
1438   for (const std::string &type : mime_send) {
1439     wl_data_source_offer(data_source->data_source, type.c_str());
1440   }
1441 
1442   if (!d->inputs.empty() && d->inputs[0]->data_device) {
1443     wl_data_device_set_selection(
1444         d->inputs[0]->data_device, data_source->data_source, data_source->source_serial);
1445   }
1446 }
1447 
getNumDisplays() const1448 GHOST_TUns8 GHOST_SystemWayland::getNumDisplays() const
1449 {
1450   return d ? GHOST_TUns8(d->outputs.size()) : 0;
1451 }
1452 
getCursorPosition(GHOST_TInt32 & x,GHOST_TInt32 & y) const1453 GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const
1454 {
1455   if (!d->inputs.empty() && (d->inputs[0]->focus_pointer != nullptr)) {
1456     x = d->inputs[0]->x;
1457     y = d->inputs[0]->y;
1458     return GHOST_kSuccess;
1459   }
1460   else {
1461     return GHOST_kFailure;
1462   }
1463 }
1464 
setCursorPosition(GHOST_TInt32,GHOST_TInt32)1465 GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(GHOST_TInt32 /*x*/, GHOST_TInt32 /*y*/)
1466 {
1467   return GHOST_kFailure;
1468 }
1469 
getMainDisplayDimensions(GHOST_TUns32 & width,GHOST_TUns32 & height) const1470 void GHOST_SystemWayland::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
1471 {
1472   if (getNumDisplays() > 0) {
1473     /* We assume first output as main. */
1474     width = uint32_t(d->outputs[0]->width);
1475     height = uint32_t(d->outputs[0]->height);
1476   }
1477 }
1478 
getAllDisplayDimensions(GHOST_TUns32 & width,GHOST_TUns32 & height) const1479 void GHOST_SystemWayland::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
1480 {
1481   getMainDisplayDimensions(width, height);
1482 }
1483 
createOffscreenContext(GHOST_GLSettings glSettings)1484 GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glSettings)
1485 {
1486   /* Create new off-screen window. */
1487   wl_surface *os_surface = wl_compositor_create_surface(compositor());
1488   wl_egl_window *os_egl_window = wl_egl_window_create(os_surface, int(1), int(1));
1489 
1490   d->os_surfaces.push_back(os_surface);
1491   d->os_egl_windows.push_back(os_egl_window);
1492 
1493   GHOST_Context *context = new GHOST_ContextEGL(false,
1494                                                 EGLNativeWindowType(os_egl_window),
1495                                                 EGLNativeDisplayType(d->display),
1496                                                 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
1497                                                 3,
1498                                                 3,
1499                                                 GHOST_OPENGL_EGL_CONTEXT_FLAGS,
1500                                                 GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
1501                                                 EGL_OPENGL_API);
1502 
1503   if (context->initializeDrawingContext()) {
1504     return context;
1505   }
1506   else {
1507     delete context;
1508   }
1509 
1510   GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
1511 
1512   return nullptr;
1513 }
1514 
disposeContext(GHOST_IContext * context)1515 GHOST_TSuccess GHOST_SystemWayland::disposeContext(GHOST_IContext *context)
1516 {
1517   delete context;
1518   return GHOST_kSuccess;
1519 }
1520 
createWindow(const char * title,GHOST_TInt32 left,GHOST_TInt32 top,GHOST_TUns32 width,GHOST_TUns32 height,GHOST_TWindowState state,GHOST_TDrawingContextType type,GHOST_GLSettings glSettings,const bool exclusive,const bool is_dialog,const GHOST_IWindow * parentWindow)1521 GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
1522                                                  GHOST_TInt32 left,
1523                                                  GHOST_TInt32 top,
1524                                                  GHOST_TUns32 width,
1525                                                  GHOST_TUns32 height,
1526                                                  GHOST_TWindowState state,
1527                                                  GHOST_TDrawingContextType type,
1528                                                  GHOST_GLSettings glSettings,
1529                                                  const bool exclusive,
1530                                                  const bool is_dialog,
1531                                                  const GHOST_IWindow *parentWindow)
1532 {
1533   GHOST_WindowWayland *window = new GHOST_WindowWayland(
1534       this,
1535       title,
1536       left,
1537       top,
1538       width,
1539       height,
1540       state,
1541       parentWindow,
1542       type,
1543       is_dialog,
1544       ((glSettings.flags & GHOST_glStereoVisual) != 0),
1545       exclusive);
1546 
1547   if (window) {
1548     if (window->getValid()) {
1549       m_windowManager->addWindow(window);
1550       m_windowManager->setActiveWindow(window);
1551       pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
1552     }
1553     else {
1554       delete window;
1555       window = nullptr;
1556     }
1557   }
1558 
1559   return window;
1560 }
1561 
display()1562 wl_display *GHOST_SystemWayland::display()
1563 {
1564   return d->display;
1565 }
1566 
compositor()1567 wl_compositor *GHOST_SystemWayland::compositor()
1568 {
1569   return d->compositor;
1570 }
1571 
shell()1572 xdg_wm_base *GHOST_SystemWayland::shell()
1573 {
1574   return d->xdg_shell;
1575 }
1576 
setSelection(const std::string & selection)1577 void GHOST_SystemWayland::setSelection(const std::string &selection)
1578 {
1579   this->selection = selection;
1580 }
1581 
set_cursor_buffer(input_t * input,wl_buffer * buffer)1582 static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
1583 {
1584   input->cursor.visible = (buffer != nullptr);
1585 
1586   wl_surface_attach(input->cursor.surface, buffer, 0, 0);
1587   wl_surface_commit(input->cursor.surface);
1588 
1589   if (input->cursor.visible) {
1590     wl_surface_damage(input->cursor.surface,
1591                       0,
1592                       0,
1593                       int32_t(input->cursor.image.width),
1594                       int32_t(input->cursor.image.height));
1595     wl_pointer_set_cursor(input->pointer,
1596                           input->pointer_serial,
1597                           input->cursor.surface,
1598                           int32_t(input->cursor.image.hotspot_x),
1599                           int32_t(input->cursor.image.hotspot_y));
1600   }
1601 }
1602 
setCursorShape(GHOST_TStandardCursor shape)1603 GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
1604 {
1605   if (d->inputs.empty()) {
1606     return GHOST_kFailure;
1607   }
1608   const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) :
1609                                                          cursors.at(GHOST_kStandardCursorDefault);
1610 
1611   wl_cursor *cursor = wl_cursor_theme_get_cursor(d->cursor_theme, cursor_name.c_str());
1612 
1613   if (!cursor) {
1614     GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
1615     return GHOST_kFailure;
1616   }
1617 
1618   struct wl_cursor_image *image = cursor->images[0];
1619   struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
1620   if (!buffer) {
1621     return GHOST_kFailure;
1622   }
1623   cursor_t *c = &d->inputs[0]->cursor;
1624   c->buffer = buffer;
1625   c->image = *image;
1626 
1627   set_cursor_buffer(d->inputs[0], buffer);
1628 
1629   return GHOST_kSuccess;
1630 }
1631 
hasCursorShape(GHOST_TStandardCursor cursorShape)1632 GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
1633 {
1634   return GHOST_TSuccess(cursors.count(cursorShape) && !cursors.at(cursorShape).empty());
1635 }
1636 
setCustomCursorShape(GHOST_TUns8 * bitmap,GHOST_TUns8 * mask,int sizex,int sizey,int hotX,int hotY,bool)1637 GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(GHOST_TUns8 *bitmap,
1638                                                          GHOST_TUns8 *mask,
1639                                                          int sizex,
1640                                                          int sizey,
1641                                                          int hotX,
1642                                                          int hotY,
1643                                                          bool /*canInvertColor*/)
1644 {
1645   if (d->inputs.empty()) {
1646     return GHOST_kFailure;
1647   }
1648 
1649   cursor_t *cursor = &d->inputs[0]->cursor;
1650 
1651   static const int32_t stride = sizex * 4; /* ARGB */
1652   cursor->file_buffer->size = size_t(stride * sizey);
1653 
1654   const int fd = memfd_create("blender-cursor-custom", MFD_CLOEXEC | MFD_ALLOW_SEALING);
1655   fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
1656   posix_fallocate(fd, 0, int32_t(cursor->file_buffer->size));
1657 
1658   cursor->file_buffer->data = mmap(
1659       nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1660 
1661   struct wl_shm_pool *pool = wl_shm_create_pool(d->shm, fd, int32_t(cursor->file_buffer->size));
1662 
1663   wl_buffer *buffer = wl_shm_pool_create_buffer(
1664       pool, 0, sizex, sizey, stride, WL_SHM_FORMAT_ARGB8888);
1665 
1666   wl_shm_pool_destroy(pool);
1667   close(fd);
1668 
1669   wl_buffer_add_listener(buffer, &cursor_buffer_listener, cursor);
1670 
1671   static constexpr uint32_t black = 0xFF000000;
1672   static constexpr uint32_t white = 0xFFFFFFFF;
1673   static constexpr uint32_t transparent = 0x00000000;
1674 
1675   uint8_t datab = 0, maskb = 0;
1676   uint32_t *pixel;
1677 
1678   for (int y = 0; y < sizey; ++y) {
1679     pixel = &static_cast<uint32_t *>(cursor->file_buffer->data)[y * sizex];
1680     for (int x = 0; x < sizex; ++x) {
1681       if ((x % 8) == 0) {
1682         datab = *bitmap++;
1683         maskb = *mask++;
1684 
1685         /* Reverse bit order. */
1686         datab = uint8_t((datab * 0x0202020202ULL & 0x010884422010ULL) % 1023);
1687         maskb = uint8_t((maskb * 0x0202020202ULL & 0x010884422010ULL) % 1023);
1688       }
1689 
1690       if (maskb & 0x80) {
1691         *pixel++ = (datab & 0x80) ? white : black;
1692       }
1693       else {
1694         *pixel++ = (datab & 0x80) ? white : transparent;
1695       }
1696       datab <<= 1;
1697       maskb <<= 1;
1698     }
1699   }
1700 
1701   cursor->buffer = buffer;
1702   cursor->image.width = uint32_t(sizex);
1703   cursor->image.height = uint32_t(sizey);
1704   cursor->image.hotspot_x = uint32_t(hotX);
1705   cursor->image.hotspot_y = uint32_t(hotY);
1706 
1707   set_cursor_buffer(d->inputs[0], buffer);
1708 
1709   return GHOST_kSuccess;
1710 }
1711 
setCursorVisibility(bool visible)1712 GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
1713 {
1714   if (d->inputs.empty()) {
1715     return GHOST_kFailure;
1716   }
1717 
1718   input_t *input = d->inputs[0];
1719 
1720   cursor_t *cursor = &input->cursor;
1721   if (visible) {
1722     if (!cursor->visible) {
1723       set_cursor_buffer(input, cursor->buffer);
1724     }
1725   }
1726   else {
1727     if (cursor->visible) {
1728       set_cursor_buffer(input, nullptr);
1729     }
1730   }
1731 
1732   return GHOST_kSuccess;
1733 }
1734 
setCursorGrab(const GHOST_TGrabCursorMode mode,wl_surface * surface)1735 GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
1736                                                   wl_surface *surface)
1737 {
1738   if (d->inputs.empty()) {
1739     return GHOST_kFailure;
1740   }
1741 
1742   input_t *input = d->inputs[0];
1743 
1744   switch (mode) {
1745     case GHOST_kGrabDisable:
1746       if (input->relative_pointer) {
1747         zwp_relative_pointer_v1_destroy(input->relative_pointer);
1748         input->relative_pointer = nullptr;
1749       }
1750       if (input->locked_pointer) {
1751         zwp_locked_pointer_v1_destroy(input->locked_pointer);
1752         input->locked_pointer = nullptr;
1753       }
1754       break;
1755 
1756     case GHOST_kGrabNormal:
1757     case GHOST_kGrabWrap:
1758       input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
1759           d->relative_pointer_manager, input->pointer);
1760       zwp_relative_pointer_v1_add_listener(
1761           input->relative_pointer, &relative_pointer_listener, input);
1762       input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
1763           d->pointer_constraints,
1764           surface,
1765           input->pointer,
1766           nullptr,
1767           ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1768       break;
1769 
1770     case GHOST_kGrabHide:
1771       setCursorVisibility(false);
1772       break;
1773   }
1774 
1775   return GHOST_kSuccess;
1776 }
1777 
1778 /** \} */
1779