• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //========================================================================
2 // GLFW 3.5 Wayland - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
5 //
6 // This software is provided 'as-is', without any express or implied
7 // warranty. In no event will the authors be held liable for any damages
8 // arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it
12 // freely, subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented; you must not
15 //    claim that you wrote the original software. If you use this software
16 //    in a product, an acknowledgment in the product documentation would
17 //    be appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such, and must not
20 //    be misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source
23 //    distribution.
24 //
25 //========================================================================
26 
27 #include "internal.h"
28 
29 #if defined(_GLFW_WAYLAND)
30 
31 #include <errno.h>
32 #include <limits.h>
33 #include <linux/input.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/mman.h>
38 #include <sys/timerfd.h>
39 #include <unistd.h>
40 #include <time.h>
41 #include <assert.h>
42 
43 #include "wayland-client-protocol.h"
44 #include "xdg-shell-client-protocol.h"
45 #include "xdg-decoration-unstable-v1-client-protocol.h"
46 #include "viewporter-client-protocol.h"
47 #include "relative-pointer-unstable-v1-client-protocol.h"
48 #include "pointer-constraints-unstable-v1-client-protocol.h"
49 #include "fractional-scale-v1-client-protocol.h"
50 #include "xdg-activation-v1-client-protocol.h"
51 #include "idle-inhibit-unstable-v1-client-protocol.h"
52 
53 // NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
54 //       wl_interface pointers 'types', making it impossible to combine several unmodified
55 //       private-code files into a single compilation unit
56 // HACK: We override this name with a macro for each file, allowing them to coexist
57 
58 #define types _glfw_wayland_types
59 #include "wayland-client-protocol-code.h"
60 #undef types
61 
62 #define types _glfw_xdg_shell_types
63 #include "xdg-shell-client-protocol-code.h"
64 #undef types
65 
66 #define types _glfw_xdg_decoration_types
67 #include "xdg-decoration-unstable-v1-client-protocol-code.h"
68 #undef types
69 
70 #define types _glfw_viewporter_types
71 #include "viewporter-client-protocol-code.h"
72 #undef types
73 
74 #define types _glfw_relative_pointer_types
75 #include "relative-pointer-unstable-v1-client-protocol-code.h"
76 #undef types
77 
78 #define types _glfw_pointer_constraints_types
79 #include "pointer-constraints-unstable-v1-client-protocol-code.h"
80 #undef types
81 
82 #define types _glfw_fractional_scale_types
83 #include "fractional-scale-v1-client-protocol-code.h"
84 #undef types
85 
86 #define types _glfw_xdg_activation_types
87 #include "xdg-activation-v1-client-protocol-code.h"
88 #undef types
89 
90 #define types _glfw_idle_inhibit_types
91 #include "idle-inhibit-unstable-v1-client-protocol-code.h"
92 #undef types
93 
wmBaseHandlePing(void * userData,struct xdg_wm_base * wmBase,uint32_t serial)94 static void wmBaseHandlePing(void* userData,
95                              struct xdg_wm_base* wmBase,
96                              uint32_t serial)
97 {
98     xdg_wm_base_pong(wmBase, serial);
99 }
100 
101 static const struct xdg_wm_base_listener wmBaseListener =
102 {
103     wmBaseHandlePing
104 };
105 
registryHandleGlobal(void * userData,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)106 static void registryHandleGlobal(void* userData,
107                                  struct wl_registry* registry,
108                                  uint32_t name,
109                                  const char* interface,
110                                  uint32_t version)
111 {
112     if (strcmp(interface, "wl_compositor") == 0)
113     {
114         _glfw.wl.compositor =
115             wl_registry_bind(registry, name, &wl_compositor_interface,
116                              _glfw_min(3, version));
117     }
118     else if (strcmp(interface, "wl_subcompositor") == 0)
119     {
120         _glfw.wl.subcompositor =
121             wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);
122     }
123     else if (strcmp(interface, "wl_shm") == 0)
124     {
125         _glfw.wl.shm =
126             wl_registry_bind(registry, name, &wl_shm_interface, 1);
127     }
128     else if (strcmp(interface, "wl_output") == 0)
129     {
130         _glfwAddOutputWayland(name, version);
131     }
132     else if (strcmp(interface, "wl_seat") == 0)
133     {
134         if (!_glfw.wl.seat)
135         {
136             _glfw.wl.seat =
137                 wl_registry_bind(registry, name, &wl_seat_interface,
138                                  _glfw_min(4, version));
139             _glfwAddSeatListenerWayland(_glfw.wl.seat);
140 
141             if (wl_seat_get_version(_glfw.wl.seat) >=
142                 WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
143             {
144                 _glfw.wl.keyRepeatTimerfd =
145                     timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
146             }
147         }
148     }
149     else if (strcmp(interface, "wl_data_device_manager") == 0)
150     {
151         if (!_glfw.wl.dataDeviceManager)
152         {
153             _glfw.wl.dataDeviceManager =
154                 wl_registry_bind(registry, name,
155                                  &wl_data_device_manager_interface, 1);
156         }
157     }
158     else if (strcmp(interface, "xdg_wm_base") == 0)
159     {
160         _glfw.wl.wmBase =
161             wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
162         xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
163     }
164     else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)
165     {
166         _glfw.wl.decorationManager =
167             wl_registry_bind(registry, name,
168                              &zxdg_decoration_manager_v1_interface,
169                              1);
170     }
171     else if (strcmp(interface, "wp_viewporter") == 0)
172     {
173         _glfw.wl.viewporter =
174             wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
175     }
176     else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
177     {
178         _glfw.wl.relativePointerManager =
179             wl_registry_bind(registry, name,
180                              &zwp_relative_pointer_manager_v1_interface,
181                              1);
182     }
183     else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)
184     {
185         _glfw.wl.pointerConstraints =
186             wl_registry_bind(registry, name,
187                              &zwp_pointer_constraints_v1_interface,
188                              1);
189     }
190     else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0)
191     {
192         _glfw.wl.idleInhibitManager =
193             wl_registry_bind(registry, name,
194                              &zwp_idle_inhibit_manager_v1_interface,
195                              1);
196     }
197     else if (strcmp(interface, "xdg_activation_v1") == 0)
198     {
199         _glfw.wl.activationManager =
200             wl_registry_bind(registry, name,
201                              &xdg_activation_v1_interface,
202                              1);
203     }
204     else if (strcmp(interface, "wp_fractional_scale_manager_v1") == 0)
205     {
206         _glfw.wl.fractionalScaleManager =
207             wl_registry_bind(registry, name,
208                              &wp_fractional_scale_manager_v1_interface,
209                              1);
210     }
211 }
212 
registryHandleGlobalRemove(void * userData,struct wl_registry * registry,uint32_t name)213 static void registryHandleGlobalRemove(void* userData,
214                                        struct wl_registry* registry,
215                                        uint32_t name)
216 {
217     for (int i = 0; i < _glfw.monitorCount; ++i)
218     {
219         _GLFWmonitor* monitor = _glfw.monitors[i];
220         if (monitor->wl.name == name)
221         {
222             _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);
223             return;
224         }
225     }
226 }
227 
228 
229 static const struct wl_registry_listener registryListener =
230 {
231     registryHandleGlobal,
232     registryHandleGlobalRemove
233 };
234 
libdecorHandleError(struct libdecor * context,enum libdecor_error error,const char * message)235 void libdecorHandleError(struct libdecor* context,
236                          enum libdecor_error error,
237                          const char* message)
238 {
239     _glfwInputError(GLFW_PLATFORM_ERROR,
240                     "Wayland: libdecor error %u: %s",
241                     error, message);
242 }
243 
244 static const struct libdecor_interface libdecorInterface =
245 {
246     libdecorHandleError
247 };
248 
libdecorReadyCallback(void * userData,struct wl_callback * callback,uint32_t time)249 static void libdecorReadyCallback(void* userData,
250                                   struct wl_callback* callback,
251                                   uint32_t time)
252 {
253     _glfw.wl.libdecor.ready = GLFW_TRUE;
254 
255     assert(_glfw.wl.libdecor.callback == callback);
256     wl_callback_destroy(_glfw.wl.libdecor.callback);
257     _glfw.wl.libdecor.callback = NULL;
258 }
259 
260 static const struct wl_callback_listener libdecorReadyListener =
261 {
262     libdecorReadyCallback
263 };
264 
265 // Create key code translation tables
266 //
createKeyTables(void)267 static void createKeyTables(void)
268 {
269     memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes));
270     memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes));
271 
272     _glfw.wl.keycodes[KEY_GRAVE]      = GLFW_KEY_GRAVE_ACCENT;
273     _glfw.wl.keycodes[KEY_1]          = GLFW_KEY_1;
274     _glfw.wl.keycodes[KEY_2]          = GLFW_KEY_2;
275     _glfw.wl.keycodes[KEY_3]          = GLFW_KEY_3;
276     _glfw.wl.keycodes[KEY_4]          = GLFW_KEY_4;
277     _glfw.wl.keycodes[KEY_5]          = GLFW_KEY_5;
278     _glfw.wl.keycodes[KEY_6]          = GLFW_KEY_6;
279     _glfw.wl.keycodes[KEY_7]          = GLFW_KEY_7;
280     _glfw.wl.keycodes[KEY_8]          = GLFW_KEY_8;
281     _glfw.wl.keycodes[KEY_9]          = GLFW_KEY_9;
282     _glfw.wl.keycodes[KEY_0]          = GLFW_KEY_0;
283     _glfw.wl.keycodes[KEY_SPACE]      = GLFW_KEY_SPACE;
284     _glfw.wl.keycodes[KEY_MINUS]      = GLFW_KEY_MINUS;
285     _glfw.wl.keycodes[KEY_EQUAL]      = GLFW_KEY_EQUAL;
286     _glfw.wl.keycodes[KEY_Q]          = GLFW_KEY_Q;
287     _glfw.wl.keycodes[KEY_W]          = GLFW_KEY_W;
288     _glfw.wl.keycodes[KEY_E]          = GLFW_KEY_E;
289     _glfw.wl.keycodes[KEY_R]          = GLFW_KEY_R;
290     _glfw.wl.keycodes[KEY_T]          = GLFW_KEY_T;
291     _glfw.wl.keycodes[KEY_Y]          = GLFW_KEY_Y;
292     _glfw.wl.keycodes[KEY_U]          = GLFW_KEY_U;
293     _glfw.wl.keycodes[KEY_I]          = GLFW_KEY_I;
294     _glfw.wl.keycodes[KEY_O]          = GLFW_KEY_O;
295     _glfw.wl.keycodes[KEY_P]          = GLFW_KEY_P;
296     _glfw.wl.keycodes[KEY_LEFTBRACE]  = GLFW_KEY_LEFT_BRACKET;
297     _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
298     _glfw.wl.keycodes[KEY_A]          = GLFW_KEY_A;
299     _glfw.wl.keycodes[KEY_S]          = GLFW_KEY_S;
300     _glfw.wl.keycodes[KEY_D]          = GLFW_KEY_D;
301     _glfw.wl.keycodes[KEY_F]          = GLFW_KEY_F;
302     _glfw.wl.keycodes[KEY_G]          = GLFW_KEY_G;
303     _glfw.wl.keycodes[KEY_H]          = GLFW_KEY_H;
304     _glfw.wl.keycodes[KEY_J]          = GLFW_KEY_J;
305     _glfw.wl.keycodes[KEY_K]          = GLFW_KEY_K;
306     _glfw.wl.keycodes[KEY_L]          = GLFW_KEY_L;
307     _glfw.wl.keycodes[KEY_SEMICOLON]  = GLFW_KEY_SEMICOLON;
308     _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
309     _glfw.wl.keycodes[KEY_Z]          = GLFW_KEY_Z;
310     _glfw.wl.keycodes[KEY_X]          = GLFW_KEY_X;
311     _glfw.wl.keycodes[KEY_C]          = GLFW_KEY_C;
312     _glfw.wl.keycodes[KEY_V]          = GLFW_KEY_V;
313     _glfw.wl.keycodes[KEY_B]          = GLFW_KEY_B;
314     _glfw.wl.keycodes[KEY_N]          = GLFW_KEY_N;
315     _glfw.wl.keycodes[KEY_M]          = GLFW_KEY_M;
316     _glfw.wl.keycodes[KEY_COMMA]      = GLFW_KEY_COMMA;
317     _glfw.wl.keycodes[KEY_DOT]        = GLFW_KEY_PERIOD;
318     _glfw.wl.keycodes[KEY_SLASH]      = GLFW_KEY_SLASH;
319     _glfw.wl.keycodes[KEY_BACKSLASH]  = GLFW_KEY_BACKSLASH;
320     _glfw.wl.keycodes[KEY_ESC]        = GLFW_KEY_ESCAPE;
321     _glfw.wl.keycodes[KEY_TAB]        = GLFW_KEY_TAB;
322     _glfw.wl.keycodes[KEY_LEFTSHIFT]  = GLFW_KEY_LEFT_SHIFT;
323     _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
324     _glfw.wl.keycodes[KEY_LEFTCTRL]   = GLFW_KEY_LEFT_CONTROL;
325     _glfw.wl.keycodes[KEY_RIGHTCTRL]  = GLFW_KEY_RIGHT_CONTROL;
326     _glfw.wl.keycodes[KEY_LEFTALT]    = GLFW_KEY_LEFT_ALT;
327     _glfw.wl.keycodes[KEY_RIGHTALT]   = GLFW_KEY_RIGHT_ALT;
328     _glfw.wl.keycodes[KEY_LEFTMETA]   = GLFW_KEY_LEFT_SUPER;
329     _glfw.wl.keycodes[KEY_RIGHTMETA]  = GLFW_KEY_RIGHT_SUPER;
330     _glfw.wl.keycodes[KEY_COMPOSE]    = GLFW_KEY_MENU;
331     _glfw.wl.keycodes[KEY_NUMLOCK]    = GLFW_KEY_NUM_LOCK;
332     _glfw.wl.keycodes[KEY_CAPSLOCK]   = GLFW_KEY_CAPS_LOCK;
333     _glfw.wl.keycodes[KEY_PRINT]      = GLFW_KEY_PRINT_SCREEN;
334     _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
335     _glfw.wl.keycodes[KEY_PAUSE]      = GLFW_KEY_PAUSE;
336     _glfw.wl.keycodes[KEY_DELETE]     = GLFW_KEY_DELETE;
337     _glfw.wl.keycodes[KEY_BACKSPACE]  = GLFW_KEY_BACKSPACE;
338     _glfw.wl.keycodes[KEY_ENTER]      = GLFW_KEY_ENTER;
339     _glfw.wl.keycodes[KEY_HOME]       = GLFW_KEY_HOME;
340     _glfw.wl.keycodes[KEY_END]        = GLFW_KEY_END;
341     _glfw.wl.keycodes[KEY_PAGEUP]     = GLFW_KEY_PAGE_UP;
342     _glfw.wl.keycodes[KEY_PAGEDOWN]   = GLFW_KEY_PAGE_DOWN;
343     _glfw.wl.keycodes[KEY_INSERT]     = GLFW_KEY_INSERT;
344     _glfw.wl.keycodes[KEY_LEFT]       = GLFW_KEY_LEFT;
345     _glfw.wl.keycodes[KEY_RIGHT]      = GLFW_KEY_RIGHT;
346     _glfw.wl.keycodes[KEY_DOWN]       = GLFW_KEY_DOWN;
347     _glfw.wl.keycodes[KEY_UP]         = GLFW_KEY_UP;
348     _glfw.wl.keycodes[KEY_F1]         = GLFW_KEY_F1;
349     _glfw.wl.keycodes[KEY_F2]         = GLFW_KEY_F2;
350     _glfw.wl.keycodes[KEY_F3]         = GLFW_KEY_F3;
351     _glfw.wl.keycodes[KEY_F4]         = GLFW_KEY_F4;
352     _glfw.wl.keycodes[KEY_F5]         = GLFW_KEY_F5;
353     _glfw.wl.keycodes[KEY_F6]         = GLFW_KEY_F6;
354     _glfw.wl.keycodes[KEY_F7]         = GLFW_KEY_F7;
355     _glfw.wl.keycodes[KEY_F8]         = GLFW_KEY_F8;
356     _glfw.wl.keycodes[KEY_F9]         = GLFW_KEY_F9;
357     _glfw.wl.keycodes[KEY_F10]        = GLFW_KEY_F10;
358     _glfw.wl.keycodes[KEY_F11]        = GLFW_KEY_F11;
359     _glfw.wl.keycodes[KEY_F12]        = GLFW_KEY_F12;
360     _glfw.wl.keycodes[KEY_F13]        = GLFW_KEY_F13;
361     _glfw.wl.keycodes[KEY_F14]        = GLFW_KEY_F14;
362     _glfw.wl.keycodes[KEY_F15]        = GLFW_KEY_F15;
363     _glfw.wl.keycodes[KEY_F16]        = GLFW_KEY_F16;
364     _glfw.wl.keycodes[KEY_F17]        = GLFW_KEY_F17;
365     _glfw.wl.keycodes[KEY_F18]        = GLFW_KEY_F18;
366     _glfw.wl.keycodes[KEY_F19]        = GLFW_KEY_F19;
367     _glfw.wl.keycodes[KEY_F20]        = GLFW_KEY_F20;
368     _glfw.wl.keycodes[KEY_F21]        = GLFW_KEY_F21;
369     _glfw.wl.keycodes[KEY_F22]        = GLFW_KEY_F22;
370     _glfw.wl.keycodes[KEY_F23]        = GLFW_KEY_F23;
371     _glfw.wl.keycodes[KEY_F24]        = GLFW_KEY_F24;
372     _glfw.wl.keycodes[KEY_KPSLASH]    = GLFW_KEY_KP_DIVIDE;
373     _glfw.wl.keycodes[KEY_KPASTERISK] = GLFW_KEY_KP_MULTIPLY;
374     _glfw.wl.keycodes[KEY_KPMINUS]    = GLFW_KEY_KP_SUBTRACT;
375     _glfw.wl.keycodes[KEY_KPPLUS]     = GLFW_KEY_KP_ADD;
376     _glfw.wl.keycodes[KEY_KP0]        = GLFW_KEY_KP_0;
377     _glfw.wl.keycodes[KEY_KP1]        = GLFW_KEY_KP_1;
378     _glfw.wl.keycodes[KEY_KP2]        = GLFW_KEY_KP_2;
379     _glfw.wl.keycodes[KEY_KP3]        = GLFW_KEY_KP_3;
380     _glfw.wl.keycodes[KEY_KP4]        = GLFW_KEY_KP_4;
381     _glfw.wl.keycodes[KEY_KP5]        = GLFW_KEY_KP_5;
382     _glfw.wl.keycodes[KEY_KP6]        = GLFW_KEY_KP_6;
383     _glfw.wl.keycodes[KEY_KP7]        = GLFW_KEY_KP_7;
384     _glfw.wl.keycodes[KEY_KP8]        = GLFW_KEY_KP_8;
385     _glfw.wl.keycodes[KEY_KP9]        = GLFW_KEY_KP_9;
386     _glfw.wl.keycodes[KEY_KPDOT]      = GLFW_KEY_KP_DECIMAL;
387     _glfw.wl.keycodes[KEY_KPEQUAL]    = GLFW_KEY_KP_EQUAL;
388     _glfw.wl.keycodes[KEY_KPENTER]    = GLFW_KEY_KP_ENTER;
389     _glfw.wl.keycodes[KEY_102ND]      = GLFW_KEY_WORLD_2;
390 
391     for (int scancode = 0;  scancode < 256;  scancode++)
392     {
393         if (_glfw.wl.keycodes[scancode] > 0)
394             _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode;
395     }
396 }
397 
loadCursorTheme(void)398 static GLFWbool loadCursorTheme(void)
399 {
400     int cursorSize = 16;
401 
402     const char* sizeString = getenv("XCURSOR_SIZE");
403     if (sizeString)
404     {
405         errno = 0;
406         const long cursorSizeLong = strtol(sizeString, NULL, 10);
407         if (errno == 0 && cursorSizeLong > 0 && cursorSizeLong < INT_MAX)
408             cursorSize = (int) cursorSizeLong;
409     }
410 
411     const char* themeName = getenv("XCURSOR_THEME");
412 
413     _glfw.wl.cursorTheme = wl_cursor_theme_load(themeName, cursorSize, _glfw.wl.shm);
414     if (!_glfw.wl.cursorTheme)
415     {
416         _glfwInputError(GLFW_PLATFORM_ERROR,
417                         "Wayland: Failed to load default cursor theme");
418         return GLFW_FALSE;
419     }
420 
421     // If this happens to be NULL, we just fallback to the scale=1 version.
422     _glfw.wl.cursorThemeHiDPI =
423         wl_cursor_theme_load(themeName, cursorSize * 2, _glfw.wl.shm);
424 
425     _glfw.wl.cursorSurface = wl_compositor_create_surface(_glfw.wl.compositor);
426     _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
427     return GLFW_TRUE;
428 }
429 
430 
431 //////////////////////////////////////////////////////////////////////////
432 //////                       GLFW platform API                      //////
433 //////////////////////////////////////////////////////////////////////////
434 
_glfwConnectWayland(int platformID,_GLFWplatform * platform)435 GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
436 {
437     const _GLFWplatform wayland =
438     {
439         .platformID = GLFW_PLATFORM_WAYLAND,
440         .init = _glfwInitWayland,
441         .terminate = _glfwTerminateWayland,
442         .getCursorPos = _glfwGetCursorPosWayland,
443         .setCursorPos = _glfwSetCursorPosWayland,
444         .setCursorMode = _glfwSetCursorModeWayland,
445         .setRawMouseMotion = _glfwSetRawMouseMotionWayland,
446         .rawMouseMotionSupported = _glfwRawMouseMotionSupportedWayland,
447         .createCursor = _glfwCreateCursorWayland,
448         .createStandardCursor = _glfwCreateStandardCursorWayland,
449         .destroyCursor = _glfwDestroyCursorWayland,
450         .setCursor = _glfwSetCursorWayland,
451         .getScancodeName = _glfwGetScancodeNameWayland,
452         .getKeyScancode = _glfwGetKeyScancodeWayland,
453         .setClipboardString = _glfwSetClipboardStringWayland,
454         .getClipboardString = _glfwGetClipboardStringWayland,
455 #if defined(GLFW_BUILD_LINUX_JOYSTICK)
456         .initJoysticks = _glfwInitJoysticksLinux,
457         .terminateJoysticks = _glfwTerminateJoysticksLinux,
458         .pollJoystick = _glfwPollJoystickLinux,
459         .getMappingName = _glfwGetMappingNameLinux,
460         .updateGamepadGUID = _glfwUpdateGamepadGUIDLinux,
461 #else
462         .initJoysticks = _glfwInitJoysticksNull,
463         .terminateJoysticks = _glfwTerminateJoysticksNull,
464         .pollJoystick = _glfwPollJoystickNull,
465         .getMappingName = _glfwGetMappingNameNull,
466         .updateGamepadGUID = _glfwUpdateGamepadGUIDNull,
467 #endif
468         .freeMonitor = _glfwFreeMonitorWayland,
469         .getMonitorPos = _glfwGetMonitorPosWayland,
470         .getMonitorContentScale = _glfwGetMonitorContentScaleWayland,
471         .getMonitorWorkarea = _glfwGetMonitorWorkareaWayland,
472         .getVideoModes = _glfwGetVideoModesWayland,
473         .getVideoMode = _glfwGetVideoModeWayland,
474         .getGammaRamp = _glfwGetGammaRampWayland,
475         .setGammaRamp = _glfwSetGammaRampWayland,
476         .createWindow = _glfwCreateWindowWayland,
477         .destroyWindow = _glfwDestroyWindowWayland,
478         .setWindowTitle = _glfwSetWindowTitleWayland,
479         .setWindowIcon = _glfwSetWindowIconWayland,
480         .getWindowPos = _glfwGetWindowPosWayland,
481         .setWindowPos = _glfwSetWindowPosWayland,
482         .getWindowSize = _glfwGetWindowSizeWayland,
483         .setWindowSize = _glfwSetWindowSizeWayland,
484         .setWindowSizeLimits = _glfwSetWindowSizeLimitsWayland,
485         .setWindowAspectRatio = _glfwSetWindowAspectRatioWayland,
486         .getFramebufferSize = _glfwGetFramebufferSizeWayland,
487         .getWindowFrameSize = _glfwGetWindowFrameSizeWayland,
488         .getWindowContentScale = _glfwGetWindowContentScaleWayland,
489         .iconifyWindow = _glfwIconifyWindowWayland,
490         .restoreWindow = _glfwRestoreWindowWayland,
491         .maximizeWindow = _glfwMaximizeWindowWayland,
492         .showWindow = _glfwShowWindowWayland,
493         .hideWindow = _glfwHideWindowWayland,
494         .requestWindowAttention = _glfwRequestWindowAttentionWayland,
495         .focusWindow = _glfwFocusWindowWayland,
496         .setWindowMonitor = _glfwSetWindowMonitorWayland,
497         .windowFocused = _glfwWindowFocusedWayland,
498         .windowIconified = _glfwWindowIconifiedWayland,
499         .windowVisible = _glfwWindowVisibleWayland,
500         .windowMaximized = _glfwWindowMaximizedWayland,
501         .windowHovered = _glfwWindowHoveredWayland,
502         .framebufferTransparent = _glfwFramebufferTransparentWayland,
503         .getWindowOpacity = _glfwGetWindowOpacityWayland,
504         .setWindowResizable = _glfwSetWindowResizableWayland,
505         .setWindowDecorated = _glfwSetWindowDecoratedWayland,
506         .setWindowFloating = _glfwSetWindowFloatingWayland,
507         .setWindowOpacity = _glfwSetWindowOpacityWayland,
508         .setWindowMousePassthrough = _glfwSetWindowMousePassthroughWayland,
509         .pollEvents = _glfwPollEventsWayland,
510         .waitEvents = _glfwWaitEventsWayland,
511         .waitEventsTimeout = _glfwWaitEventsTimeoutWayland,
512         .postEmptyEvent = _glfwPostEmptyEventWayland,
513         .getEGLPlatform = _glfwGetEGLPlatformWayland,
514         .getEGLNativeDisplay = _glfwGetEGLNativeDisplayWayland,
515         .getEGLNativeWindow = _glfwGetEGLNativeWindowWayland,
516         .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWayland,
517         .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWayland,
518         .createWindowSurface = _glfwCreateWindowSurfaceWayland
519     };
520 
521     void* module = _glfwPlatformLoadModule("libwayland-client.so.0");
522     if (!module)
523     {
524         if (platformID == GLFW_PLATFORM_WAYLAND)
525         {
526             _glfwInputError(GLFW_PLATFORM_ERROR,
527                             "Wayland: Failed to load libwayland-client");
528         }
529 
530         return GLFW_FALSE;
531     }
532 
533     PFN_wl_display_connect wl_display_connect = (PFN_wl_display_connect)
534         _glfwPlatformGetModuleSymbol(module, "wl_display_connect");
535     if (!wl_display_connect)
536     {
537         if (platformID == GLFW_PLATFORM_WAYLAND)
538         {
539             _glfwInputError(GLFW_PLATFORM_ERROR,
540                             "Wayland: Failed to load libwayland-client entry point");
541         }
542 
543         _glfwPlatformFreeModule(module);
544         return GLFW_FALSE;
545     }
546 
547     struct wl_display* display = wl_display_connect(NULL);
548     if (!display)
549     {
550         if (platformID == GLFW_PLATFORM_WAYLAND)
551             _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to connect to display");
552 
553         _glfwPlatformFreeModule(module);
554         return GLFW_FALSE;
555     }
556 
557     _glfw.wl.display = display;
558     _glfw.wl.client.handle = module;
559 
560     *platform = wayland;
561     return GLFW_TRUE;
562 }
563 
_glfwInitWayland(void)564 int _glfwInitWayland(void)
565 {
566     // These must be set before any failure checks
567     _glfw.wl.keyRepeatTimerfd = -1;
568     _glfw.wl.cursorTimerfd = -1;
569 
570     _glfw.wl.tag = glfwGetVersionString();
571 
572     _glfw.wl.client.display_flush = (PFN_wl_display_flush)
573         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_flush");
574     _glfw.wl.client.display_cancel_read = (PFN_wl_display_cancel_read)
575         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_cancel_read");
576     _glfw.wl.client.display_dispatch_pending = (PFN_wl_display_dispatch_pending)
577         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_dispatch_pending");
578     _glfw.wl.client.display_read_events = (PFN_wl_display_read_events)
579         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_read_events");
580     _glfw.wl.client.display_disconnect = (PFN_wl_display_disconnect)
581         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_disconnect");
582     _glfw.wl.client.display_roundtrip = (PFN_wl_display_roundtrip)
583         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_roundtrip");
584     _glfw.wl.client.display_get_fd = (PFN_wl_display_get_fd)
585         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_get_fd");
586     _glfw.wl.client.display_prepare_read = (PFN_wl_display_prepare_read)
587         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_prepare_read");
588     _glfw.wl.client.proxy_marshal = (PFN_wl_proxy_marshal)
589         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal");
590     _glfw.wl.client.proxy_add_listener = (PFN_wl_proxy_add_listener)
591         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_add_listener");
592     _glfw.wl.client.proxy_destroy = (PFN_wl_proxy_destroy)
593         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_destroy");
594     _glfw.wl.client.proxy_marshal_constructor = (PFN_wl_proxy_marshal_constructor)
595         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_constructor");
596     _glfw.wl.client.proxy_marshal_constructor_versioned = (PFN_wl_proxy_marshal_constructor_versioned)
597         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_constructor_versioned");
598     _glfw.wl.client.proxy_get_user_data = (PFN_wl_proxy_get_user_data)
599         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_user_data");
600     _glfw.wl.client.proxy_set_user_data = (PFN_wl_proxy_set_user_data)
601         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_user_data");
602     _glfw.wl.client.proxy_get_tag = (PFN_wl_proxy_get_tag)
603         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_tag");
604     _glfw.wl.client.proxy_set_tag = (PFN_wl_proxy_set_tag)
605         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_tag");
606     _glfw.wl.client.proxy_get_version = (PFN_wl_proxy_get_version)
607         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_version");
608     _glfw.wl.client.proxy_marshal_flags = (PFN_wl_proxy_marshal_flags)
609         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_flags");
610 
611     if (!_glfw.wl.client.display_flush ||
612         !_glfw.wl.client.display_cancel_read ||
613         !_glfw.wl.client.display_dispatch_pending ||
614         !_glfw.wl.client.display_read_events ||
615         !_glfw.wl.client.display_disconnect ||
616         !_glfw.wl.client.display_roundtrip ||
617         !_glfw.wl.client.display_get_fd ||
618         !_glfw.wl.client.display_prepare_read ||
619         !_glfw.wl.client.proxy_marshal ||
620         !_glfw.wl.client.proxy_add_listener ||
621         !_glfw.wl.client.proxy_destroy ||
622         !_glfw.wl.client.proxy_marshal_constructor ||
623         !_glfw.wl.client.proxy_marshal_constructor_versioned ||
624         !_glfw.wl.client.proxy_get_user_data ||
625         !_glfw.wl.client.proxy_set_user_data ||
626         !_glfw.wl.client.proxy_get_tag ||
627         !_glfw.wl.client.proxy_set_tag)
628     {
629         _glfwInputError(GLFW_PLATFORM_ERROR,
630                         "Wayland: Failed to load libwayland-client entry point");
631         return GLFW_FALSE;
632     }
633 
634     _glfw.wl.cursor.handle = _glfwPlatformLoadModule("libwayland-cursor.so.0");
635     if (!_glfw.wl.cursor.handle)
636     {
637         _glfwInputError(GLFW_PLATFORM_ERROR,
638                         "Wayland: Failed to load libwayland-cursor");
639         return GLFW_FALSE;
640     }
641 
642     _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)
643         _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_load");
644     _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)
645         _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
646     _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)
647         _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
648     _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)
649         _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
650 
651     _glfw.wl.egl.handle = _glfwPlatformLoadModule("libwayland-egl.so.1");
652     if (!_glfw.wl.egl.handle)
653     {
654         _glfwInputError(GLFW_PLATFORM_ERROR,
655                         "Wayland: Failed to load libwayland-egl");
656         return GLFW_FALSE;
657     }
658 
659     _glfw.wl.egl.window_create = (PFN_wl_egl_window_create)
660         _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_create");
661     _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)
662         _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_destroy");
663     _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)
664         _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_resize");
665 
666     _glfw.wl.xkb.handle = _glfwPlatformLoadModule("libxkbcommon.so.0");
667     if (!_glfw.wl.xkb.handle)
668     {
669         _glfwInputError(GLFW_PLATFORM_ERROR,
670                         "Wayland: Failed to load libxkbcommon");
671         return GLFW_FALSE;
672     }
673 
674     _glfw.wl.xkb.context_new = (PFN_xkb_context_new)
675         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_context_new");
676     _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref)
677         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_context_unref");
678     _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string)
679         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string");
680     _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref)
681         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_unref");
682     _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index)
683         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index");
684     _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats)
685         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats");
686     _glfw.wl.xkb.keymap_key_get_syms_by_level = (PFN_xkb_keymap_key_get_syms_by_level)
687         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_key_get_syms_by_level");
688     _glfw.wl.xkb.state_new = (PFN_xkb_state_new)
689         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_new");
690     _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref)
691         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_unref");
692     _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms)
693         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_key_get_syms");
694     _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask)
695         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_update_mask");
696     _glfw.wl.xkb.state_key_get_layout = (PFN_xkb_state_key_get_layout)
697         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_key_get_layout");
698     _glfw.wl.xkb.state_mod_index_is_active = (PFN_xkb_state_mod_index_is_active)
699         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_mod_index_is_active");
700     _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale)
701         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale");
702     _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref)
703         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_table_unref");
704     _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new)
705         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_new");
706     _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref)
707         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_unref");
708     _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed)
709         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_feed");
710     _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status)
711         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");
712     _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
713         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
714 
715     if (!_glfw.wl.xkb.context_new ||
716         !_glfw.wl.xkb.context_unref ||
717         !_glfw.wl.xkb.keymap_new_from_string ||
718         !_glfw.wl.xkb.keymap_unref ||
719         !_glfw.wl.xkb.keymap_mod_get_index ||
720         !_glfw.wl.xkb.keymap_key_repeats ||
721         !_glfw.wl.xkb.keymap_key_get_syms_by_level ||
722         !_glfw.wl.xkb.state_new ||
723         !_glfw.wl.xkb.state_unref ||
724         !_glfw.wl.xkb.state_key_get_syms ||
725         !_glfw.wl.xkb.state_update_mask ||
726         !_glfw.wl.xkb.state_key_get_layout ||
727         !_glfw.wl.xkb.state_mod_index_is_active ||
728         !_glfw.wl.xkb.compose_table_new_from_locale ||
729         !_glfw.wl.xkb.compose_table_unref ||
730         !_glfw.wl.xkb.compose_state_new ||
731         !_glfw.wl.xkb.compose_state_unref ||
732         !_glfw.wl.xkb.compose_state_feed ||
733         !_glfw.wl.xkb.compose_state_get_status ||
734         !_glfw.wl.xkb.compose_state_get_one_sym)
735     {
736         _glfwInputError(GLFW_PLATFORM_ERROR,
737                         "Wayland: Failed to load all entry points from libxkbcommon");
738         return GLFW_FALSE;
739     }
740 
741     if (_glfw.hints.init.wl.libdecorMode == GLFW_WAYLAND_PREFER_LIBDECOR)
742         _glfw.wl.libdecor.handle = _glfwPlatformLoadModule("libdecor-0.so.0");
743 
744     if (_glfw.wl.libdecor.handle)
745     {
746         _glfw.wl.libdecor.libdecor_new_ = (PFN_libdecor_new)
747             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_new");
748         _glfw.wl.libdecor.libdecor_unref_ = (PFN_libdecor_unref)
749             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_unref");
750         _glfw.wl.libdecor.libdecor_get_fd_ = (PFN_libdecor_get_fd)
751             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_get_fd");
752         _glfw.wl.libdecor.libdecor_dispatch_ = (PFN_libdecor_dispatch)
753             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_dispatch");
754         _glfw.wl.libdecor.libdecor_decorate_ = (PFN_libdecor_decorate)
755             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_decorate");
756         _glfw.wl.libdecor.libdecor_frame_unref_ = (PFN_libdecor_frame_unref)
757             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unref");
758         _glfw.wl.libdecor.libdecor_frame_set_app_id_ = (PFN_libdecor_frame_set_app_id)
759             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_app_id");
760         _glfw.wl.libdecor.libdecor_frame_set_title_ = (PFN_libdecor_frame_set_title)
761             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_title");
762         _glfw.wl.libdecor.libdecor_frame_set_minimized_ = (PFN_libdecor_frame_set_minimized)
763             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_minimized");
764         _glfw.wl.libdecor.libdecor_frame_set_fullscreen_ = (PFN_libdecor_frame_set_fullscreen)
765             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_fullscreen");
766         _glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ = (PFN_libdecor_frame_unset_fullscreen)
767             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_fullscreen");
768         _glfw.wl.libdecor.libdecor_frame_map_ = (PFN_libdecor_frame_map)
769             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_map");
770         _glfw.wl.libdecor.libdecor_frame_commit_ = (PFN_libdecor_frame_commit)
771             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_commit");
772         _glfw.wl.libdecor.libdecor_frame_set_min_content_size_ = (PFN_libdecor_frame_set_min_content_size)
773             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_min_content_size");
774         _glfw.wl.libdecor.libdecor_frame_set_max_content_size_ = (PFN_libdecor_frame_set_max_content_size)
775             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_max_content_size");
776         _glfw.wl.libdecor.libdecor_frame_set_maximized_ = (PFN_libdecor_frame_set_maximized)
777             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_maximized");
778         _glfw.wl.libdecor.libdecor_frame_unset_maximized_ = (PFN_libdecor_frame_unset_maximized)
779             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_maximized");
780         _glfw.wl.libdecor.libdecor_frame_set_capabilities_ = (PFN_libdecor_frame_set_capabilities)
781             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_capabilities");
782         _glfw.wl.libdecor.libdecor_frame_unset_capabilities_ = (PFN_libdecor_frame_unset_capabilities)
783             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_capabilities");
784         _glfw.wl.libdecor.libdecor_frame_set_visibility_ = (PFN_libdecor_frame_set_visibility)
785             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_visibility");
786         _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ = (PFN_libdecor_frame_get_xdg_toplevel)
787             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_get_xdg_toplevel");
788         _glfw.wl.libdecor.libdecor_configuration_get_content_size_ = (PFN_libdecor_configuration_get_content_size)
789             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_configuration_get_content_size");
790         _glfw.wl.libdecor.libdecor_configuration_get_window_state_ = (PFN_libdecor_configuration_get_window_state)
791             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_configuration_get_window_state");
792         _glfw.wl.libdecor.libdecor_state_new_ = (PFN_libdecor_state_new)
793             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_state_new");
794         _glfw.wl.libdecor.libdecor_state_free_ = (PFN_libdecor_state_free)
795             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_state_free");
796 
797         if (!_glfw.wl.libdecor.libdecor_new_ ||
798             !_glfw.wl.libdecor.libdecor_unref_ ||
799             !_glfw.wl.libdecor.libdecor_get_fd_ ||
800             !_glfw.wl.libdecor.libdecor_dispatch_ ||
801             !_glfw.wl.libdecor.libdecor_decorate_ ||
802             !_glfw.wl.libdecor.libdecor_frame_unref_ ||
803             !_glfw.wl.libdecor.libdecor_frame_set_app_id_ ||
804             !_glfw.wl.libdecor.libdecor_frame_set_title_ ||
805             !_glfw.wl.libdecor.libdecor_frame_set_minimized_ ||
806             !_glfw.wl.libdecor.libdecor_frame_set_fullscreen_ ||
807             !_glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ ||
808             !_glfw.wl.libdecor.libdecor_frame_map_ ||
809             !_glfw.wl.libdecor.libdecor_frame_commit_ ||
810             !_glfw.wl.libdecor.libdecor_frame_set_min_content_size_ ||
811             !_glfw.wl.libdecor.libdecor_frame_set_max_content_size_ ||
812             !_glfw.wl.libdecor.libdecor_frame_set_maximized_ ||
813             !_glfw.wl.libdecor.libdecor_frame_unset_maximized_ ||
814             !_glfw.wl.libdecor.libdecor_frame_set_capabilities_ ||
815             !_glfw.wl.libdecor.libdecor_frame_unset_capabilities_ ||
816             !_glfw.wl.libdecor.libdecor_frame_set_visibility_ ||
817             !_glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ ||
818             !_glfw.wl.libdecor.libdecor_configuration_get_content_size_ ||
819             !_glfw.wl.libdecor.libdecor_configuration_get_window_state_ ||
820             !_glfw.wl.libdecor.libdecor_state_new_ ||
821             !_glfw.wl.libdecor.libdecor_state_free_)
822         {
823             _glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
824             memset(&_glfw.wl.libdecor, 0, sizeof(_glfw.wl.libdecor));
825         }
826     }
827 
828     _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
829     wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
830 
831     createKeyTables();
832 
833     _glfw.wl.xkb.context = xkb_context_new(0);
834     if (!_glfw.wl.xkb.context)
835     {
836         _glfwInputError(GLFW_PLATFORM_ERROR,
837                         "Wayland: Failed to initialize xkb context");
838         return GLFW_FALSE;
839     }
840 
841     // Sync so we got all registry objects
842     wl_display_roundtrip(_glfw.wl.display);
843 
844     // Sync so we got all initial output events
845     wl_display_roundtrip(_glfw.wl.display);
846 
847     if (_glfw.wl.libdecor.handle)
848     {
849         _glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface);
850         if (_glfw.wl.libdecor.context)
851         {
852             // Perform an initial dispatch and flush to get the init started
853             libdecor_dispatch(_glfw.wl.libdecor.context, 0);
854 
855             // Create sync point to "know" when libdecor is ready for use
856             _glfw.wl.libdecor.callback = wl_display_sync(_glfw.wl.display);
857             wl_callback_add_listener(_glfw.wl.libdecor.callback,
858                                      &libdecorReadyListener,
859                                      NULL);
860         }
861     }
862 
863     if (!_glfw.wl.wmBase)
864     {
865         _glfwInputError(GLFW_PLATFORM_ERROR,
866                         "Wayland: Failed to find xdg-shell in your compositor");
867         return GLFW_FALSE;
868     }
869 
870     if (!_glfw.wl.shm)
871     {
872         _glfwInputError(GLFW_PLATFORM_ERROR,
873                         "Wayland: Failed to find wl_shm in your compositor");
874         return GLFW_FALSE;
875     }
876 
877     if (!loadCursorTheme())
878         return GLFW_FALSE;
879 
880     if (_glfw.wl.seat && _glfw.wl.dataDeviceManager)
881     {
882         _glfw.wl.dataDevice =
883             wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
884                                                    _glfw.wl.seat);
885         _glfwAddDataDeviceListenerWayland(_glfw.wl.dataDevice);
886     }
887 
888     return GLFW_TRUE;
889 }
890 
_glfwTerminateWayland(void)891 void _glfwTerminateWayland(void)
892 {
893     _glfwTerminateEGL();
894     _glfwTerminateOSMesa();
895 
896     if (_glfw.wl.libdecor.context)
897     {
898         // Allow libdecor to finish receiving all its requested globals
899         // and ensure the associated sync callback object is destroyed
900         while (!_glfw.wl.libdecor.ready)
901             _glfwWaitEventsWayland();
902 
903         libdecor_unref(_glfw.wl.libdecor.context);
904     }
905 
906     if (_glfw.wl.libdecor.handle)
907     {
908         _glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
909         _glfw.wl.libdecor.handle = NULL;
910     }
911 
912     if (_glfw.wl.egl.handle)
913     {
914         _glfwPlatformFreeModule(_glfw.wl.egl.handle);
915         _glfw.wl.egl.handle = NULL;
916     }
917 
918     if (_glfw.wl.xkb.composeState)
919         xkb_compose_state_unref(_glfw.wl.xkb.composeState);
920     if (_glfw.wl.xkb.keymap)
921         xkb_keymap_unref(_glfw.wl.xkb.keymap);
922     if (_glfw.wl.xkb.state)
923         xkb_state_unref(_glfw.wl.xkb.state);
924     if (_glfw.wl.xkb.context)
925         xkb_context_unref(_glfw.wl.xkb.context);
926     if (_glfw.wl.xkb.handle)
927     {
928         _glfwPlatformFreeModule(_glfw.wl.xkb.handle);
929         _glfw.wl.xkb.handle = NULL;
930     }
931 
932     if (_glfw.wl.cursorTheme)
933         wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
934     if (_glfw.wl.cursorThemeHiDPI)
935         wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
936     if (_glfw.wl.cursor.handle)
937     {
938         _glfwPlatformFreeModule(_glfw.wl.cursor.handle);
939         _glfw.wl.cursor.handle = NULL;
940     }
941 
942     for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
943         wl_data_offer_destroy(_glfw.wl.offers[i].offer);
944 
945     _glfw_free(_glfw.wl.offers);
946 
947     if (_glfw.wl.cursorSurface)
948         wl_surface_destroy(_glfw.wl.cursorSurface);
949     if (_glfw.wl.subcompositor)
950         wl_subcompositor_destroy(_glfw.wl.subcompositor);
951     if (_glfw.wl.compositor)
952         wl_compositor_destroy(_glfw.wl.compositor);
953     if (_glfw.wl.shm)
954         wl_shm_destroy(_glfw.wl.shm);
955     if (_glfw.wl.viewporter)
956         wp_viewporter_destroy(_glfw.wl.viewporter);
957     if (_glfw.wl.decorationManager)
958         zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
959     if (_glfw.wl.wmBase)
960         xdg_wm_base_destroy(_glfw.wl.wmBase);
961     if (_glfw.wl.selectionOffer)
962         wl_data_offer_destroy(_glfw.wl.selectionOffer);
963     if (_glfw.wl.dragOffer)
964         wl_data_offer_destroy(_glfw.wl.dragOffer);
965     if (_glfw.wl.selectionSource)
966         wl_data_source_destroy(_glfw.wl.selectionSource);
967     if (_glfw.wl.dataDevice)
968         wl_data_device_destroy(_glfw.wl.dataDevice);
969     if (_glfw.wl.dataDeviceManager)
970         wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
971     if (_glfw.wl.pointer)
972         wl_pointer_destroy(_glfw.wl.pointer);
973     if (_glfw.wl.keyboard)
974         wl_keyboard_destroy(_glfw.wl.keyboard);
975     if (_glfw.wl.seat)
976         wl_seat_destroy(_glfw.wl.seat);
977     if (_glfw.wl.relativePointerManager)
978         zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
979     if (_glfw.wl.pointerConstraints)
980         zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
981     if (_glfw.wl.idleInhibitManager)
982         zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager);
983     if (_glfw.wl.activationManager)
984         xdg_activation_v1_destroy(_glfw.wl.activationManager);
985     if (_glfw.wl.fractionalScaleManager)
986         wp_fractional_scale_manager_v1_destroy(_glfw.wl.fractionalScaleManager);
987     if (_glfw.wl.registry)
988         wl_registry_destroy(_glfw.wl.registry);
989     if (_glfw.wl.display)
990     {
991         wl_display_flush(_glfw.wl.display);
992         wl_display_disconnect(_glfw.wl.display);
993     }
994 
995     if (_glfw.wl.keyRepeatTimerfd >= 0)
996         close(_glfw.wl.keyRepeatTimerfd);
997     if (_glfw.wl.cursorTimerfd >= 0)
998         close(_glfw.wl.cursorTimerfd);
999 
1000     _glfw_free(_glfw.wl.clipboardString);
1001 }
1002 
1003 #endif // _GLFW_WAYLAND
1004 
1005