2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
22 #include "../../SDL_internal.h"
24 #if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
26 #include "../SDL_sysvideo.h"
27 #include "../../events/SDL_windowevents_c.h"
28 #include "../SDL_egl_c.h"
29 #include "SDL_waylandevents_c.h"
30 #include "SDL_waylandwindow.h"
31 #include "SDL_waylandvideo.h"
32 #include "SDL_waylandtouch.h"
33 #include "SDL_waylanddyn.h"
34 #include "SDL_hints.h"
36 #include "xdg-shell-client-protocol.h"
37 #include "xdg-shell-unstable-v6-client-protocol.h"
38 #include "xdg-decoration-unstable-v1-client-protocol.h"
39 #include "org-kde-kwin-server-decoration-manager-client-protocol.h"
41 static float get_window_scale_factor(SDL_Window *window) {
42 return ((SDL_WindowData*)window->driverdata)->scale_factor;
45 /* On modern desktops, we probably will use the xdg-shell protocol instead
46 of wl_shell, but wl_shell might be useful on older Wayland installs that
47 don't have the newer protocol, or embedded things that don't have a full
51 handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
54 wl_shell_surface_pong(shell_surface, serial);
58 handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
59 uint32_t edges, int32_t width, int32_t height)
61 SDL_WindowData *wind = (SDL_WindowData *)data;
62 SDL_Window *window = wind->sdlwindow;
64 /* wl_shell_surface spec states that this is a suggestion.
65 Ignore if less than or greater than max/min size. */
67 if (width == 0 || height == 0) {
71 if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
72 if ((window->flags & SDL_WINDOW_RESIZABLE)) {
73 if (window->max_w > 0) {
74 width = SDL_min(width, window->max_w);
76 width = SDL_max(width, window->min_w);
78 if (window->max_h > 0) {
79 height = SDL_min(height, window->max_h);
81 height = SDL_max(height, window->min_h);
87 wind->resize.width = width;
88 wind->resize.height = height;
89 wind->resize.pending = SDL_TRUE;
91 if (!(window->flags & SDL_WINDOW_OPENGL)) {
92 Wayland_HandlePendingResize(window); /* OpenGL windows handle this in SwapWindow */
97 handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
101 static const struct wl_shell_surface_listener shell_surface_listener_wl = {
102 handle_ping_wl_shell_surface,
103 handle_configure_wl_shell_surface,
104 handle_popup_done_wl_shell_surface
111 handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
113 SDL_WindowData *wind = (SDL_WindowData *)data;
114 SDL_Window *window = wind->sdlwindow;
115 struct wl_region *region;
117 if (!wind->shell_surface.zxdg.initial_configure_seen) {
120 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height);
121 window->w = wind->resize.width;
122 window->h = wind->resize.height;
124 wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
125 if (wind->egl_window) {
126 WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
129 zxdg_surface_v6_ack_configure(zxdg, serial);
131 region = wl_compositor_create_region(wind->waylandData->compositor);
132 wl_region_add(region, 0, 0, window->w, window->h);
133 wl_surface_set_opaque_region(wind->surface, region);
134 wl_region_destroy(region);
136 wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
138 wind->resize.pending = SDL_TRUE;
139 wind->resize.configure = SDL_TRUE;
140 wind->resize.serial = serial;
141 if (!(window->flags & SDL_WINDOW_OPENGL)) {
142 Wayland_HandlePendingResize(window); /* OpenGL windows handle this in SwapWindow */
147 static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
148 handle_configure_zxdg_shell_surface
153 handle_configure_zxdg_toplevel(void *data,
154 struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
157 struct wl_array *states)
159 SDL_WindowData *wind = (SDL_WindowData *)data;
160 SDL_Window *window = wind->sdlwindow;
162 enum zxdg_toplevel_v6_state *state;
163 SDL_bool fullscreen = SDL_FALSE;
164 wl_array_for_each(state, states) {
165 if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
166 fullscreen = SDL_TRUE;
171 if (width == 0 || height == 0) {
172 width = window->windowed.w;
173 height = window->windowed.h;
176 /* zxdg_toplevel spec states that this is a suggestion.
177 Ignore if less than or greater than max/min size. */
179 if ((window->flags & SDL_WINDOW_RESIZABLE)) {
180 if (window->max_w > 0) {
181 width = SDL_min(width, window->max_w);
183 width = SDL_max(width, window->min_w);
185 if (window->max_h > 0) {
186 height = SDL_min(height, window->max_h);
188 height = SDL_max(height, window->min_h);
190 wind->resize.width = window->w;
191 wind->resize.height = window->h;
196 if (width == 0 || height == 0) {
197 wind->resize.width = window->w;
198 wind->resize.height = window->h;
202 wind->resize.width = width;
203 wind->resize.height = height;
207 handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
209 SDL_WindowData *window = (SDL_WindowData *)data;
210 SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
213 static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
214 handle_configure_zxdg_toplevel,
215 handle_close_zxdg_toplevel
221 handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial)
223 SDL_WindowData *wind = (SDL_WindowData *)data;
224 SDL_Window *window = wind->sdlwindow;
225 struct wl_region *region;
227 if (!wind->shell_surface.xdg.initial_configure_seen) {
230 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height);
231 window->w = wind->resize.width;
232 window->h = wind->resize.height;
234 wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
235 if (wind->egl_window) {
236 WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
239 xdg_surface_ack_configure(xdg, serial);
241 region = wl_compositor_create_region(wind->waylandData->compositor);
242 wl_region_add(region, 0, 0, window->w, window->h);
243 wl_surface_set_opaque_region(wind->surface, region);
244 wl_region_destroy(region);
246 wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
248 wind->resize.pending = SDL_TRUE;
249 wind->resize.configure = SDL_TRUE;
250 wind->resize.serial = serial;
251 if (!(window->flags & SDL_WINDOW_OPENGL)) {
252 Wayland_HandlePendingResize(window); /* OpenGL windows handle this in SwapWindow */
257 static const struct xdg_surface_listener shell_surface_listener_xdg = {
258 handle_configure_xdg_shell_surface
263 handle_configure_xdg_toplevel(void *data,
264 struct xdg_toplevel *xdg_toplevel,
267 struct wl_array *states)
269 SDL_WindowData *wind = (SDL_WindowData *)data;
270 SDL_Window *window = wind->sdlwindow;
272 enum xdg_toplevel_state *state;
273 SDL_bool fullscreen = SDL_FALSE;
274 wl_array_for_each(state, states) {
275 if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
276 fullscreen = SDL_TRUE;
281 if (width == 0 || height == 0) {
282 width = window->windowed.w;
283 height = window->windowed.h;
286 /* xdg_toplevel spec states that this is a suggestion.
287 Ignore if less than or greater than max/min size. */
289 if ((window->flags & SDL_WINDOW_RESIZABLE)) {
290 if (window->max_w > 0) {
291 width = SDL_min(width, window->max_w);
293 width = SDL_max(width, window->min_w);
295 if (window->max_h > 0) {
296 height = SDL_min(height, window->max_h);
298 height = SDL_max(height, window->min_h);
300 wind->resize.width = window->w;
301 wind->resize.height = window->h;
306 if (width == 0 || height == 0) {
307 wind->resize.width = window->w;
308 wind->resize.height = window->h;
312 wind->resize.width = width;
313 wind->resize.height = height;
317 handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
319 SDL_WindowData *window = (SDL_WindowData *)data;
320 SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
323 static const struct xdg_toplevel_listener toplevel_listener_xdg = {
324 handle_configure_xdg_toplevel,
325 handle_close_xdg_toplevel
331 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
333 handle_onscreen_visibility(void *data,
334 struct qt_extended_surface *qt_extended_surface, int32_t visible)
339 handle_set_generic_property(void *data,
340 struct qt_extended_surface *qt_extended_surface, const char *name,
341 struct wl_array *value)
346 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
348 SDL_WindowData *window = (SDL_WindowData *)data;
349 SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
352 static const struct qt_extended_surface_listener extended_surface_listener = {
353 handle_onscreen_visibility,
354 handle_set_generic_property,
357 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
360 update_scale_factor(SDL_WindowData *window) {
361 float old_factor = window->scale_factor, new_factor = 0.0;
364 if (!(window->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
368 if (!window->num_outputs) {
369 new_factor = old_factor;
372 if (FULLSCREEN_VISIBLE(window->sdlwindow) && window->sdlwindow->fullscreen_mode.driverdata) {
373 new_factor = ((SDL_WaylandOutputData*)(wl_output_get_user_data(window->sdlwindow->fullscreen_mode.driverdata)))->scale_factor;
376 for (i = 0; i < window->num_outputs; i++) {
377 float factor = ((SDL_WaylandOutputData*)(wl_output_get_user_data(window->outputs[i])))->scale_factor;
378 if (factor > new_factor) {
383 if (new_factor != old_factor) {
384 /* force the resize event to trigger, as the logical size didn't change */
385 window->resize.width = window->sdlwindow->w;
386 window->resize.height = window->sdlwindow->h;
387 window->resize.scale_factor = new_factor;
388 window->resize.pending = SDL_TRUE;
389 if (!(window->sdlwindow->flags & SDL_WINDOW_OPENGL)) {
390 Wayland_HandlePendingResize(window->sdlwindow); /* OpenGL windows handle this in SwapWindow */
396 handle_surface_enter(void *data, struct wl_surface *surface,
397 struct wl_output *output) {
398 SDL_WindowData *window = data;
400 window->outputs = SDL_realloc(window->outputs, (window->num_outputs + 1) * sizeof *window->outputs);
401 window->outputs[window->num_outputs++] = output;
402 update_scale_factor(window);
406 handle_surface_leave(void *data, struct wl_surface *surface,
407 struct wl_output *output) {
408 SDL_WindowData *window = data;
411 for (i = 0; i < window->num_outputs; i++) {
412 if (window->outputs[i] == output) { /* remove this one */
413 if (i == (window->num_outputs-1)) {
414 window->outputs[i] = NULL;
416 SDL_memmove(&window->outputs[i], &window->outputs[i+1], sizeof (output) * ((window->num_outputs - i) - 1));
418 window->num_outputs--;
423 if (window->num_outputs == 0) {
424 SDL_free(window->outputs);
425 window->outputs = NULL;
428 update_scale_factor(window);
431 static const struct wl_surface_listener surface_listener = {
432 handle_surface_enter,
437 Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
439 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
440 const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
441 (((Uint32) info->version.minor) * 10000) +
442 (((Uint32) info->version.patch)));
444 /* Before 2.0.6, it was possible to build an SDL with Wayland support
445 (SDL_SysWMinfo will be large enough to hold Wayland info), but build
446 your app against SDL headers that didn't have Wayland support
447 (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
448 to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
449 overflow memory on the stack or heap. To protect against this, we've
450 padded out the struct unconditionally in the headers and Wayland will
451 just return an error for older apps using this function. Those apps
452 will need to be recompiled against newer headers or not use Wayland,
453 maybe by forcing SDL_VIDEODRIVER=x11. */
454 if (version < 2000006) {
455 info->subsystem = SDL_SYSWM_UNKNOWN;
456 SDL_SetError("Version must be 2.0.6 or newer");
460 info->info.wl.display = data->waylandData->display;
461 info->info.wl.surface = data->surface;
462 info->info.wl.shell_surface = data->shell_surface.wl;
463 info->subsystem = SDL_SYSWM_WAYLAND;
469 Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
471 return 0; /* just succeed, the real work is done elsewhere. */
475 SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
477 const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
478 SDL_WindowData *wind = window->driverdata;
480 if (viddata->shell.xdg) {
482 xdg_toplevel_set_fullscreen(wind->shell_surface.xdg.roleobj.toplevel, output);
484 xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel);
486 } else if (viddata->shell.zxdg) {
488 zxdg_toplevel_v6_set_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel, output);
490 zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel);
494 wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
495 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
498 wl_shell_surface_set_toplevel(wind->shell_surface.wl);
502 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
505 void Wayland_ShowWindow(_THIS, SDL_Window *window)
507 struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
508 SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
511 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
513 QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
514 const char *oldValue, const char *newValue)
516 struct qt_extended_surface *qt_extended_surface = userdata;
522 if (strcmp(name, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION) == 0) {
523 int32_t orientation = QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION;
525 if (newValue != NULL) {
526 if (strcmp(newValue, "portrait") == 0) {
527 orientation = QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION;
528 } else if (strcmp(newValue, "landscape") == 0) {
529 orientation = QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION;
530 } else if (strcmp(newValue, "inverted-portrait") == 0) {
531 orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION;
532 } else if (strcmp(newValue, "inverted-landscape") == 0) {
533 orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION;
537 qt_extended_surface_set_content_orientation(qt_extended_surface, orientation);
538 } else if (strcmp(name, SDL_HINT_QTWAYLAND_WINDOW_FLAGS) == 0) {
541 if (newValue != NULL) {
542 char *tmp = strdup(newValue);
543 char *saveptr = NULL;
545 char *flag = strtok_r(tmp, " ", &saveptr);
547 if (strcmp(flag, "OverridesSystemGestures") == 0) {
548 flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES;
549 } else if (strcmp(flag, "StaysOnTop") == 0) {
550 flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP;
551 } else if (strcmp(flag, "BypassWindowManager") == 0) {
552 // See https://github.com/qtproject/qtwayland/commit/fb4267103d
553 flags |= 4 /* QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER */;
556 flag = strtok_r(NULL, " ", &saveptr);
562 qt_extended_surface_set_window_flags(qt_extended_surface, flags);
566 static void QtExtendedSurface_Subscribe(struct qt_extended_surface *surface, const char *name)
568 SDL_AddHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
571 static void QtExtendedSurface_Unsubscribe(struct qt_extended_surface *surface, const char *name)
573 SDL_DelHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
575 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
578 Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
579 SDL_VideoDisplay * _display, SDL_bool fullscreen)
581 struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output;
582 SetFullscreen(_this, window, fullscreen ? output : NULL);
586 Wayland_RestoreWindow(_THIS, SDL_Window * window)
588 SDL_WindowData *wind = window->driverdata;
589 const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
591 if (viddata->shell.xdg) {
592 } else if (viddata->shell.zxdg) {
594 wl_shell_surface_set_toplevel(wind->shell_surface.wl);
597 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
601 Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
603 SDL_WindowData *wind = window->driverdata;
604 const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
605 if ((viddata->decoration_manager) && (wind->server_decoration)) {
606 const enum zxdg_toplevel_decoration_v1_mode mode = bordered ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
607 zxdg_toplevel_decoration_v1_set_mode(wind->server_decoration, mode);
608 } else if ((viddata->kwin_server_decoration_manager) && (wind->kwin_server_decoration)) {
609 const enum org_kde_kwin_server_decoration_manager_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
610 org_kde_kwin_server_decoration_request_mode(wind->kwin_server_decoration, mode);
615 Wayland_MaximizeWindow(_THIS, SDL_Window * window)
617 SDL_WindowData *wind = window->driverdata;
618 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
620 if (viddata->shell.xdg) {
621 xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel);
622 } else if (viddata->shell.zxdg) {
623 zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel);
625 wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
628 WAYLAND_wl_display_flush( viddata->display );
632 Wayland_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
634 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
637 Wayland_input_confine_pointer(window, data->input);
639 Wayland_input_unconfine_pointer(data->input);
642 int Wayland_CreateWindow(_THIS, SDL_Window *window)
644 SDL_WindowData *data;
646 struct wl_region *region;
648 data = SDL_calloc(1, sizeof *data);
650 return SDL_OutOfMemory();
652 c = _this->driverdata;
653 window->driverdata = data;
655 if (!(window->flags & SDL_WINDOW_VULKAN)) {
656 if (!(window->flags & SDL_WINDOW_OPENGL)) {
657 SDL_GL_LoadLibrary(NULL);
658 window->flags |= SDL_WINDOW_OPENGL;
662 if (window->x == SDL_WINDOWPOS_UNDEFINED) {
665 if (window->y == SDL_WINDOWPOS_UNDEFINED) {
669 data->waylandData = c;
670 data->sdlwindow = window;
672 data->scale_factor = 1.0;
674 if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
676 for (i=0; i < SDL_GetVideoDevice()->num_displays; i++) {
677 float scale = ((SDL_WaylandOutputData*)SDL_GetVideoDevice()->displays[i].driverdata)->scale_factor;
678 if (scale > data->scale_factor) {
679 data->scale_factor = scale;
684 data->resize.pending = SDL_FALSE;
685 data->resize.width = window->w;
686 data->resize.height = window->h;
687 data->resize.scale_factor = data->scale_factor;
689 data->outputs = NULL;
690 data->num_outputs = 0;
693 wl_compositor_create_surface(c->compositor);
694 wl_surface_add_listener(data->surface, &surface_listener, data);
697 data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface);
698 /* !!! FIXME: add popup role */
699 data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
700 xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
701 xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
702 } else if (c->shell.zxdg) {
703 data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
704 /* !!! FIXME: add popup role */
705 data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
706 zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
707 zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
709 data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
710 wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
713 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
714 if (c->surface_extension) {
715 data->extended_surface = qt_surface_extension_get_extended_surface(
716 c->surface_extension, data->surface);
718 QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
719 QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
721 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
723 if (window->flags & SDL_WINDOW_OPENGL) {
724 data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
725 window->w * data->scale_factor, window->h * data->scale_factor);
727 /* Create the GLES window surface */
728 data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
730 if (data->egl_surface == EGL_NO_SURFACE) {
731 return SDL_SetError("failed to create an EGL window surface");
736 if (data->shell_surface.xdg.surface) {
737 xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
738 xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data);
740 } else if (c->shell.zxdg) {
741 if (data->shell_surface.zxdg.surface) {
742 zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
743 zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
746 if (data->shell_surface.wl) {
747 wl_shell_surface_set_user_data(data->shell_surface.wl, data);
748 wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
752 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
753 if (data->extended_surface) {
754 qt_extended_surface_set_user_data(data->extended_surface, data);
755 qt_extended_surface_add_listener(data->extended_surface,
756 &extended_surface_listener, data);
758 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
760 if (c->decoration_manager && c->shell.xdg && data->shell_surface.xdg.surface) {
761 data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel);
762 if (data->server_decoration) {
763 const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
764 const enum zxdg_toplevel_decoration_v1_mode mode = bordered ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
765 zxdg_toplevel_decoration_v1_set_mode(data->server_decoration, mode);
767 } else if (c->kwin_server_decoration_manager) {
768 data->kwin_server_decoration = org_kde_kwin_server_decoration_manager_create(c->kwin_server_decoration_manager, data->surface);
769 if (data->kwin_server_decoration) {
770 const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
771 const enum org_kde_kwin_server_decoration_manager_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
772 org_kde_kwin_server_decoration_request_mode(data->kwin_server_decoration, mode);
776 region = wl_compositor_create_region(c->compositor);
777 wl_region_add(region, 0, 0, window->w, window->h);
778 wl_surface_set_opaque_region(data->surface, region);
779 wl_region_destroy(region);
781 if (c->relative_mouse_mode) {
782 Wayland_input_lock_pointer(c->input);
785 wl_surface_commit(data->surface);
786 WAYLAND_wl_display_flush(c->display);
788 /* we have to wait until the surface gets a "configure" event, or
789 use of this surface will fail. This is a new rule for xdg_shell. */
791 if (data->shell_surface.xdg.surface) {
792 while (!data->shell_surface.xdg.initial_configure_seen) {
793 WAYLAND_wl_display_flush(c->display);
794 WAYLAND_wl_display_dispatch(c->display);
797 } else if (c->shell.zxdg) {
798 if (data->shell_surface.zxdg.surface) {
799 while (!data->shell_surface.zxdg.initial_configure_seen) {
800 WAYLAND_wl_display_flush(c->display);
801 WAYLAND_wl_display_dispatch(c->display);
811 Wayland_HandlePendingResize(SDL_Window *window)
813 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
815 if (data->resize.pending) {
816 struct wl_region *region;
817 if (data->scale_factor != data->resize.scale_factor) {
821 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, data->resize.width, data->resize.height);
822 window->w = data->resize.width;
823 window->h = data->resize.height;
824 data->scale_factor = data->resize.scale_factor;
825 wl_surface_set_buffer_scale(data->surface, data->scale_factor);
826 if (data->egl_window) {
827 WAYLAND_wl_egl_window_resize(data->egl_window, window->w * data->scale_factor, window->h * data->scale_factor, 0, 0);
830 if (data->resize.configure) {
831 if (data->waylandData->shell.xdg) {
832 xdg_surface_ack_configure(data->shell_surface.xdg.surface, data->resize.serial);
833 } else if (data->waylandData->shell.zxdg) {
834 zxdg_surface_v6_ack_configure(data->shell_surface.zxdg.surface, data->resize.serial);
836 data->resize.configure = SDL_FALSE;
839 region = wl_compositor_create_region(data->waylandData->compositor);
840 wl_region_add(region, 0, 0, window->w, window->h);
841 wl_surface_set_opaque_region(data->surface, region);
842 wl_region_destroy(region);
844 data->resize.pending = SDL_FALSE;
848 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
850 SDL_VideoData *data = _this->driverdata;
851 SDL_WindowData *wind = window->driverdata;
852 struct wl_region *region;
854 wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
856 if (wind->egl_window) {
857 WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
860 region = wl_compositor_create_region(data->compositor);
861 wl_region_add(region, 0, 0, window->w, window->h);
862 wl_surface_set_opaque_region(wind->surface, region);
863 wl_region_destroy(region);
866 void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
868 SDL_WindowData *wind = window->driverdata;
869 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
871 if (window->title != NULL) {
872 if (viddata->shell.xdg) {
873 xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, window->title);
874 } else if (viddata->shell.zxdg) {
875 zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title);
877 wl_shell_surface_set_title(wind->shell_surface.wl, window->title);
881 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
884 void Wayland_DestroyWindow(_THIS, SDL_Window *window)
886 SDL_VideoData *data = _this->driverdata;
887 SDL_WindowData *wind = window->driverdata;
890 if (wind->egl_surface) {
891 SDL_EGL_DestroySurface(_this, wind->egl_surface);
893 if (wind->egl_window) {
894 WAYLAND_wl_egl_window_destroy(wind->egl_window);
897 if (wind->server_decoration) {
898 zxdg_toplevel_decoration_v1_destroy(wind->server_decoration);
901 if (wind->kwin_server_decoration) {
902 org_kde_kwin_server_decoration_release(wind->kwin_server_decoration);
905 if (data->shell.xdg) {
906 if (wind->shell_surface.xdg.roleobj.toplevel) {
907 xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
909 if (wind->shell_surface.zxdg.surface) {
910 xdg_surface_destroy(wind->shell_surface.xdg.surface);
912 } else if (data->shell.zxdg) {
913 if (wind->shell_surface.zxdg.roleobj.toplevel) {
914 zxdg_toplevel_v6_destroy(wind->shell_surface.zxdg.roleobj.toplevel);
916 if (wind->shell_surface.zxdg.surface) {
917 zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface);
920 if (wind->shell_surface.wl) {
921 wl_shell_surface_destroy(wind->shell_surface.wl);
925 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
926 if (wind->extended_surface) {
927 QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
928 QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
929 qt_extended_surface_destroy(wind->extended_surface);
931 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
932 wl_surface_destroy(wind->surface);
935 WAYLAND_wl_display_flush(data->display);
937 window->driverdata = NULL;
940 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
942 /* vi: set ts=4 sw=4 expandtab: */