1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | |
22 | #include "../../SDL_internal.h" |
23 | |
24 | #if SDL_VIDEO_DRIVER_WAYLAND |
25 | |
26 | #include "SDL_video.h" |
27 | #include "SDL_mouse.h" |
28 | #include "SDL_stdinc.h" |
29 | #include "../../events/SDL_events_c.h" |
30 | |
31 | #include "SDL_waylandvideo.h" |
32 | #include "SDL_waylandevents_c.h" |
33 | #include "SDL_waylandwindow.h" |
34 | #include "SDL_waylandopengles.h" |
35 | #include "SDL_waylandmouse.h" |
36 | #include "SDL_waylandkeyboard.h" |
37 | #include "SDL_waylandtouch.h" |
38 | #include "SDL_waylandclipboard.h" |
39 | #include "SDL_waylandvulkan.h" |
40 | |
41 | #include <sys/types.h> |
42 | #include <unistd.h> |
43 | #include <fcntl.h> |
44 | #include <xkbcommon/xkbcommon.h> |
45 | |
46 | #include "SDL_waylanddyn.h" |
47 | #include <wayland-util.h> |
48 | |
49 | #include "xdg-shell-client-protocol.h" |
50 | #include "xdg-shell-unstable-v6-client-protocol.h" |
51 | #include "xdg-decoration-unstable-v1-client-protocol.h" |
52 | #include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h" |
53 | #include "idle-inhibit-unstable-v1-client-protocol.h" |
54 | |
55 | #define WAYLANDVID_DRIVER_NAME "wayland" |
56 | |
57 | /* Initialization/Query functions */ |
58 | static int |
59 | Wayland_VideoInit(_THIS); |
60 | |
61 | static void |
62 | Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display); |
63 | static int |
64 | Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode); |
65 | |
66 | static void |
67 | Wayland_VideoQuit(_THIS); |
68 | |
69 | /* Find out what class name we should use |
70 | * Based on src/video/x11/SDL_x11video.c */ |
71 | static char * |
72 | get_classname() |
73 | { |
74 | /* !!! FIXME: this is probably wrong, albeit harmless in many common cases. From protocol spec: |
75 | "The surface class identifies the general class of applications |
76 | to which the surface belongs. A common convention is to use the |
77 | file name (or the full path if it is a non-standard location) of |
78 | the application's .desktop file as the class." */ |
79 | |
80 | char *spot; |
81 | #if defined(__LINUX__) || defined(__FREEBSD__) |
82 | char procfile[1024]; |
83 | char linkfile[1024]; |
84 | int linksize; |
85 | #endif |
86 | |
87 | /* First allow environment variable override */ |
88 | spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS" ); |
89 | if (spot) { |
90 | return SDL_strdup(spot); |
91 | } else { |
92 | /* Fallback to the "old" envvar */ |
93 | spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS" ); |
94 | if (spot) { |
95 | return SDL_strdup(spot); |
96 | } |
97 | } |
98 | |
99 | /* Next look at the application's executable name */ |
100 | #if defined(__LINUX__) || defined(__FREEBSD__) |
101 | #if defined(__LINUX__) |
102 | SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe" , getpid()); |
103 | #elif defined(__FREEBSD__) |
104 | SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file" , |
105 | getpid()); |
106 | #else |
107 | #error Where can we find the executable name? |
108 | #endif |
109 | linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1); |
110 | if (linksize > 0) { |
111 | linkfile[linksize] = '\0'; |
112 | spot = SDL_strrchr(linkfile, '/'); |
113 | if (spot) { |
114 | return SDL_strdup(spot + 1); |
115 | } else { |
116 | return SDL_strdup(linkfile); |
117 | } |
118 | } |
119 | #endif /* __LINUX__ || __FREEBSD__ */ |
120 | |
121 | /* Finally use the default we've used forever */ |
122 | return SDL_strdup("SDL_App" ); |
123 | } |
124 | |
125 | static void |
126 | Wayland_DeleteDevice(SDL_VideoDevice *device) |
127 | { |
128 | SDL_VideoData *data = (SDL_VideoData *)device->driverdata; |
129 | if (data->display) { |
130 | WAYLAND_wl_display_flush(data->display); |
131 | WAYLAND_wl_display_disconnect(data->display); |
132 | } |
133 | SDL_free(data); |
134 | SDL_free(device); |
135 | SDL_WAYLAND_UnloadSymbols(); |
136 | } |
137 | |
138 | static SDL_VideoDevice * |
139 | Wayland_CreateDevice(int devindex) |
140 | { |
141 | SDL_VideoDevice *device; |
142 | SDL_VideoData *data; |
143 | struct wl_display *display; |
144 | |
145 | if (!SDL_WAYLAND_LoadSymbols()) { |
146 | return NULL; |
147 | } |
148 | |
149 | display = WAYLAND_wl_display_connect(NULL); |
150 | if (display == NULL) { |
151 | SDL_WAYLAND_UnloadSymbols(); |
152 | return NULL; |
153 | } |
154 | |
155 | data = SDL_calloc(1, sizeof(*data)); |
156 | if (data == NULL) { |
157 | WAYLAND_wl_display_disconnect(display); |
158 | SDL_WAYLAND_UnloadSymbols(); |
159 | SDL_OutOfMemory(); |
160 | return NULL; |
161 | } |
162 | |
163 | data->display = display; |
164 | |
165 | /* Initialize all variables that we clean on shutdown */ |
166 | device = SDL_calloc(1, sizeof(SDL_VideoDevice)); |
167 | if (!device) { |
168 | SDL_free(data); |
169 | WAYLAND_wl_display_disconnect(display); |
170 | SDL_WAYLAND_UnloadSymbols(); |
171 | SDL_OutOfMemory(); |
172 | return NULL; |
173 | } |
174 | |
175 | device->driverdata = data; |
176 | |
177 | /* Set the function pointers */ |
178 | device->VideoInit = Wayland_VideoInit; |
179 | device->VideoQuit = Wayland_VideoQuit; |
180 | device->SetDisplayMode = Wayland_SetDisplayMode; |
181 | device->GetDisplayModes = Wayland_GetDisplayModes; |
182 | device->GetWindowWMInfo = Wayland_GetWindowWMInfo; |
183 | device->SuspendScreenSaver = Wayland_SuspendScreenSaver; |
184 | |
185 | device->PumpEvents = Wayland_PumpEvents; |
186 | |
187 | device->GL_SwapWindow = Wayland_GLES_SwapWindow; |
188 | device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval; |
189 | device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval; |
190 | device->GL_GetDrawableSize = Wayland_GLES_GetDrawableSize; |
191 | device->GL_MakeCurrent = Wayland_GLES_MakeCurrent; |
192 | device->GL_CreateContext = Wayland_GLES_CreateContext; |
193 | device->GL_LoadLibrary = Wayland_GLES_LoadLibrary; |
194 | device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary; |
195 | device->GL_GetProcAddress = Wayland_GLES_GetProcAddress; |
196 | device->GL_DeleteContext = Wayland_GLES_DeleteContext; |
197 | |
198 | device->CreateSDLWindow = Wayland_CreateWindow; |
199 | device->ShowWindow = Wayland_ShowWindow; |
200 | device->SetWindowFullscreen = Wayland_SetWindowFullscreen; |
201 | device->MaximizeWindow = Wayland_MaximizeWindow; |
202 | device->MinimizeWindow = Wayland_MinimizeWindow; |
203 | device->SetWindowMouseGrab = Wayland_SetWindowMouseGrab; |
204 | device->SetWindowKeyboardGrab = Wayland_SetWindowKeyboardGrab; |
205 | device->RestoreWindow = Wayland_RestoreWindow; |
206 | device->SetWindowBordered = Wayland_SetWindowBordered; |
207 | device->SetWindowResizable = Wayland_SetWindowResizable; |
208 | device->SetWindowSize = Wayland_SetWindowSize; |
209 | device->SetWindowMinimumSize = Wayland_SetWindowMinimumSize; |
210 | device->SetWindowMaximumSize = Wayland_SetWindowMaximumSize; |
211 | device->SetWindowTitle = Wayland_SetWindowTitle; |
212 | device->DestroyWindow = Wayland_DestroyWindow; |
213 | device->SetWindowHitTest = Wayland_SetWindowHitTest; |
214 | |
215 | device->SetClipboardText = Wayland_SetClipboardText; |
216 | device->GetClipboardText = Wayland_GetClipboardText; |
217 | device->HasClipboardText = Wayland_HasClipboardText; |
218 | device->StartTextInput = Wayland_StartTextInput; |
219 | device->StopTextInput = Wayland_StopTextInput; |
220 | device->SetTextInputRect = Wayland_SetTextInputRect; |
221 | |
222 | #if SDL_VIDEO_VULKAN |
223 | device->Vulkan_LoadLibrary = Wayland_Vulkan_LoadLibrary; |
224 | device->Vulkan_UnloadLibrary = Wayland_Vulkan_UnloadLibrary; |
225 | device->Vulkan_GetInstanceExtensions = Wayland_Vulkan_GetInstanceExtensions; |
226 | device->Vulkan_CreateSurface = Wayland_Vulkan_CreateSurface; |
227 | device->Vulkan_GetDrawableSize = Wayland_Vulkan_GetDrawableSize; |
228 | #endif |
229 | |
230 | device->free = Wayland_DeleteDevice; |
231 | |
232 | return device; |
233 | } |
234 | |
235 | VideoBootStrap Wayland_bootstrap = { |
236 | WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver" , |
237 | Wayland_CreateDevice |
238 | }; |
239 | |
240 | static void |
241 | display_handle_geometry(void *data, |
242 | struct wl_output *output, |
243 | int x, int y, |
244 | int physical_width, |
245 | int physical_height, |
246 | int subpixel, |
247 | const char *make, |
248 | const char *model, |
249 | int transform) |
250 | |
251 | { |
252 | SDL_WaylandOutputData *driverdata = data; |
253 | |
254 | driverdata->placeholder.name = SDL_strdup(model); |
255 | driverdata->transform = transform; |
256 | } |
257 | |
258 | static void |
259 | display_handle_mode(void *data, |
260 | struct wl_output *output, |
261 | uint32_t flags, |
262 | int width, |
263 | int height, |
264 | int refresh) |
265 | { |
266 | SDL_WaylandOutputData* driverdata = data; |
267 | SDL_DisplayMode mode; |
268 | |
269 | if (flags & WL_OUTPUT_MODE_CURRENT) { |
270 | driverdata->width = width; |
271 | driverdata->height = height; |
272 | driverdata->refresh = refresh; |
273 | } |
274 | |
275 | /* Note that the width/height are NOT multiplied by scale_factor! |
276 | * This is intentional and is designed to get the unscaled modes, which is |
277 | * important for high-DPI games intending to use the display mode as the |
278 | * target drawable size. The scaled desktop mode will be added at the end |
279 | * when display_handle_done is called (see below). |
280 | */ |
281 | SDL_zero(mode); |
282 | mode.format = SDL_PIXELFORMAT_RGB888; |
283 | if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { |
284 | mode.w = height; |
285 | mode.h = width; |
286 | } else { |
287 | mode.w = width; |
288 | mode.h = height; |
289 | } |
290 | mode.refresh_rate = refresh / 1000; /* mHz to Hz */ |
291 | mode.driverdata = driverdata->output; |
292 | SDL_AddDisplayMode(&driverdata->placeholder, &mode); |
293 | } |
294 | |
295 | static void |
296 | display_handle_done(void *data, |
297 | struct wl_output *output) |
298 | { |
299 | SDL_WaylandOutputData* driverdata = data; |
300 | SDL_DisplayMode mode; |
301 | |
302 | if (driverdata->done) |
303 | return; |
304 | |
305 | driverdata->done = SDL_TRUE; |
306 | |
307 | SDL_zero(mode); |
308 | mode.format = SDL_PIXELFORMAT_RGB888; |
309 | if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { |
310 | mode.w = driverdata->height / driverdata->scale_factor; |
311 | mode.h = driverdata->width / driverdata->scale_factor; |
312 | } else { |
313 | mode.w = driverdata->width / driverdata->scale_factor; |
314 | mode.h = driverdata->height / driverdata->scale_factor; |
315 | } |
316 | mode.refresh_rate = driverdata->refresh / 1000; /* mHz to Hz */ |
317 | mode.driverdata = driverdata->output; |
318 | SDL_AddDisplayMode(&driverdata->placeholder, &mode); |
319 | driverdata->placeholder.current_mode = mode; |
320 | driverdata->placeholder.desktop_mode = mode; |
321 | |
322 | driverdata->placeholder.driverdata = driverdata; |
323 | SDL_AddVideoDisplay(&driverdata->placeholder, SDL_FALSE); |
324 | SDL_zero(driverdata->placeholder); |
325 | } |
326 | |
327 | static void |
328 | display_handle_scale(void *data, |
329 | struct wl_output *output, |
330 | int32_t factor) |
331 | { |
332 | SDL_WaylandOutputData *driverdata = data; |
333 | driverdata->scale_factor = factor; |
334 | } |
335 | |
336 | static const struct wl_output_listener output_listener = { |
337 | display_handle_geometry, |
338 | display_handle_mode, |
339 | display_handle_done, |
340 | display_handle_scale |
341 | }; |
342 | |
343 | static void |
344 | Wayland_add_display(SDL_VideoData *d, uint32_t id) |
345 | { |
346 | struct wl_output *output; |
347 | SDL_WaylandOutputData *data; |
348 | |
349 | output = wl_registry_bind(d->registry, id, &wl_output_interface, 2); |
350 | if (!output) { |
351 | SDL_SetError("Failed to retrieve output." ); |
352 | return; |
353 | } |
354 | data = SDL_malloc(sizeof *data); |
355 | SDL_zerop(data); |
356 | data->output = output; |
357 | data->scale_factor = 1.0; |
358 | |
359 | wl_output_add_listener(output, &output_listener, data); |
360 | } |
361 | |
362 | #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH |
363 | static void |
364 | windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager, |
365 | int32_t show_is_fullscreen) |
366 | { |
367 | } |
368 | |
369 | static void |
370 | windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager) |
371 | { |
372 | SDL_SendQuit(); |
373 | } |
374 | |
375 | static const struct qt_windowmanager_listener windowmanager_listener = { |
376 | windowmanager_hints, |
377 | windowmanager_quit, |
378 | }; |
379 | #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ |
380 | |
381 | |
382 | static void |
383 | handle_ping_zxdg_shell(void *data, struct zxdg_shell_v6 *zxdg, uint32_t serial) |
384 | { |
385 | zxdg_shell_v6_pong(zxdg, serial); |
386 | } |
387 | |
388 | static const struct zxdg_shell_v6_listener shell_listener_zxdg = { |
389 | handle_ping_zxdg_shell |
390 | }; |
391 | |
392 | |
393 | static void |
394 | handle_ping_xdg_wm_base(void *data, struct xdg_wm_base *xdg, uint32_t serial) |
395 | { |
396 | xdg_wm_base_pong(xdg, serial); |
397 | } |
398 | |
399 | static const struct xdg_wm_base_listener shell_listener_xdg = { |
400 | handle_ping_xdg_wm_base |
401 | }; |
402 | |
403 | |
404 | static void |
405 | display_handle_global(void *data, struct wl_registry *registry, uint32_t id, |
406 | const char *interface, uint32_t version) |
407 | { |
408 | SDL_VideoData *d = data; |
409 | |
410 | /*printf("WAYLAND INTERFACE: %s\n", interface);*/ |
411 | |
412 | if (strcmp(interface, "wl_compositor" ) == 0) { |
413 | d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, SDL_min(3, version)); |
414 | } else if (strcmp(interface, "wl_output" ) == 0) { |
415 | Wayland_add_display(d, id); |
416 | } else if (strcmp(interface, "wl_seat" ) == 0) { |
417 | Wayland_display_add_input(d, id, version); |
418 | } else if (strcmp(interface, "xdg_wm_base" ) == 0) { |
419 | d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1); |
420 | xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL); |
421 | } else if (strcmp(interface, "zxdg_shell_v6" ) == 0) { |
422 | d->shell.zxdg = wl_registry_bind(d->registry, id, &zxdg_shell_v6_interface, 1); |
423 | zxdg_shell_v6_add_listener(d->shell.zxdg, &shell_listener_zxdg, NULL); |
424 | } else if (strcmp(interface, "wl_shell" ) == 0) { |
425 | d->shell.wl = wl_registry_bind(d->registry, id, &wl_shell_interface, 1); |
426 | } else if (strcmp(interface, "wl_shm" ) == 0) { |
427 | d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); |
428 | d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm); |
429 | } else if (strcmp(interface, "zwp_relative_pointer_manager_v1" ) == 0) { |
430 | Wayland_display_add_relative_pointer_manager(d, id); |
431 | } else if (strcmp(interface, "zwp_pointer_constraints_v1" ) == 0) { |
432 | Wayland_display_add_pointer_constraints(d, id); |
433 | } else if (strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1" ) == 0) { |
434 | d->key_inhibitor_manager = wl_registry_bind(d->registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1); |
435 | } else if (strcmp(interface, "zwp_idle_inhibit_manager_v1" ) == 0) { |
436 | d->idle_inhibit_manager = wl_registry_bind(d->registry, id, &zwp_idle_inhibit_manager_v1_interface, 1); |
437 | } else if (strcmp(interface, "wl_data_device_manager" ) == 0) { |
438 | Wayland_add_data_device_manager(d, id, version); |
439 | } else if (strcmp(interface, "zxdg_decoration_manager_v1" ) == 0) { |
440 | d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1); |
441 | |
442 | #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH |
443 | } else if (strcmp(interface, "qt_touch_extension" ) == 0) { |
444 | Wayland_touch_create(d, id); |
445 | } else if (strcmp(interface, "qt_surface_extension" ) == 0) { |
446 | d->surface_extension = wl_registry_bind(registry, id, |
447 | &qt_surface_extension_interface, 1); |
448 | } else if (strcmp(interface, "qt_windowmanager" ) == 0) { |
449 | d->windowmanager = wl_registry_bind(registry, id, |
450 | &qt_windowmanager_interface, 1); |
451 | qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d); |
452 | #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ |
453 | } |
454 | } |
455 | |
456 | static void |
457 | display_remove_global(void *data, struct wl_registry *registry, uint32_t id) {} |
458 | |
459 | static const struct wl_registry_listener registry_listener = { |
460 | display_handle_global, |
461 | display_remove_global |
462 | }; |
463 | |
464 | int |
465 | Wayland_VideoInit(_THIS) |
466 | { |
467 | SDL_VideoData *data = (SDL_VideoData*)_this->driverdata; |
468 | |
469 | data->xkb_context = WAYLAND_xkb_context_new(0); |
470 | if (!data->xkb_context) { |
471 | return SDL_SetError("Failed to create XKB context" ); |
472 | } |
473 | |
474 | data->registry = wl_display_get_registry(data->display); |
475 | if (data->registry == NULL) { |
476 | return SDL_SetError("Failed to get the Wayland registry" ); |
477 | } |
478 | |
479 | wl_registry_add_listener(data->registry, ®istry_listener, data); |
480 | |
481 | // First roundtrip to receive all registry objects. |
482 | WAYLAND_wl_display_roundtrip(data->display); |
483 | |
484 | // Second roundtrip to receive all output events. |
485 | WAYLAND_wl_display_roundtrip(data->display); |
486 | |
487 | Wayland_InitMouse(); |
488 | |
489 | /* Get the surface class name, usually the name of the application */ |
490 | data->classname = get_classname(); |
491 | |
492 | WAYLAND_wl_display_flush(data->display); |
493 | |
494 | Wayland_InitKeyboard(_this); |
495 | |
496 | #if SDL_USE_LIBDBUS |
497 | SDL_DBus_Init(); |
498 | #endif |
499 | |
500 | return 0; |
501 | } |
502 | |
503 | static void |
504 | Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display) |
505 | { |
506 | // Nothing to do here, everything was already done in the wl_output |
507 | // callbacks. |
508 | } |
509 | |
510 | static int |
511 | Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) |
512 | { |
513 | return SDL_Unsupported(); |
514 | } |
515 | |
516 | void |
517 | Wayland_VideoQuit(_THIS) |
518 | { |
519 | SDL_VideoData *data = _this->driverdata; |
520 | int i, j; |
521 | |
522 | Wayland_FiniMouse (); |
523 | |
524 | for (i = 0; i < _this->num_displays; ++i) { |
525 | SDL_VideoDisplay *display = &_this->displays[i]; |
526 | |
527 | wl_output_destroy(((SDL_WaylandOutputData*)display->driverdata)->output); |
528 | SDL_free(display->driverdata); |
529 | display->driverdata = NULL; |
530 | |
531 | for (j = display->num_display_modes; j--;) { |
532 | display->display_modes[j].driverdata = NULL; |
533 | } |
534 | display->desktop_mode.driverdata = NULL; |
535 | } |
536 | |
537 | Wayland_display_destroy_input(data); |
538 | Wayland_display_destroy_pointer_constraints(data); |
539 | Wayland_display_destroy_relative_pointer_manager(data); |
540 | |
541 | if (data->idle_inhibit_manager) |
542 | zwp_idle_inhibit_manager_v1_destroy(data->idle_inhibit_manager); |
543 | |
544 | if (data->key_inhibitor_manager) |
545 | zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(data->key_inhibitor_manager); |
546 | |
547 | if (data->xkb_context) { |
548 | WAYLAND_xkb_context_unref(data->xkb_context); |
549 | data->xkb_context = NULL; |
550 | } |
551 | #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH |
552 | if (data->windowmanager) |
553 | qt_windowmanager_destroy(data->windowmanager); |
554 | |
555 | if (data->surface_extension) |
556 | qt_surface_extension_destroy(data->surface_extension); |
557 | |
558 | Wayland_touch_destroy(data); |
559 | #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ |
560 | |
561 | if (data->data_device_manager) |
562 | wl_data_device_manager_destroy(data->data_device_manager); |
563 | |
564 | if (data->shm) |
565 | wl_shm_destroy(data->shm); |
566 | |
567 | if (data->cursor_theme) |
568 | WAYLAND_wl_cursor_theme_destroy(data->cursor_theme); |
569 | |
570 | if (data->shell.wl) |
571 | wl_shell_destroy(data->shell.wl); |
572 | |
573 | if (data->shell.xdg) |
574 | xdg_wm_base_destroy(data->shell.xdg); |
575 | |
576 | if (data->shell.zxdg) |
577 | zxdg_shell_v6_destroy(data->shell.zxdg); |
578 | |
579 | if (data->decoration_manager) |
580 | zxdg_decoration_manager_v1_destroy(data->decoration_manager); |
581 | |
582 | if (data->compositor) |
583 | wl_compositor_destroy(data->compositor); |
584 | |
585 | if (data->registry) |
586 | wl_registry_destroy(data->registry); |
587 | |
588 | Wayland_QuitKeyboard(_this); |
589 | |
590 | SDL_free(data->classname); |
591 | } |
592 | |
593 | #endif /* SDL_VIDEO_DRIVER_WAYLAND */ |
594 | |
595 | /* vi: set ts=4 sw=4 expandtab: */ |
596 | |