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, ®istryListener, 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