src/video/wayland/SDL_waylandwindow.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 31 Oct 2018 15:03:41 -0400
changeset 12381 dc9108cd4340
parent 12298 c4d5e502c1f4
parent 12367 8256aaaafe54
child 12400 28303fca62bd
permissions -rw-r--r--
Merge SDL-ryan-batching-renderer branch to default.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 && SDL_VIDEO_OPENGL_EGL
    25 
    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"
    35 
    36 #include "xdg-shell-client-protocol.h"
    37 #include "xdg-shell-unstable-v6-client-protocol.h"
    38 #include "org-kde-kwin-server-decoration-manager-client-protocol.h"
    39 
    40 /* On modern desktops, we probably will use the xdg-shell protocol instead
    41    of wl_shell, but wl_shell might be useful on older Wayland installs that
    42    don't have the newer protocol, or embedded things that don't have a full
    43    window manager. */
    44 
    45 static void
    46 handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
    47             uint32_t serial)
    48 {
    49     wl_shell_surface_pong(shell_surface, serial);
    50 }
    51 
    52 static void
    53 handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
    54                  uint32_t edges, int32_t width, int32_t height)
    55 {
    56     SDL_WindowData *wind = (SDL_WindowData *)data;
    57     SDL_Window *window = wind->sdlwindow;
    58     struct wl_region *region;
    59 
    60     /* wl_shell_surface spec states that this is a suggestion.
    61        Ignore if less than or greater than max/min size. */
    62 
    63     if (width == 0 || height == 0) {
    64         return;
    65     }
    66 
    67     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
    68         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
    69             if (window->max_w > 0) {
    70                 width = SDL_min(width, window->max_w);
    71             } 
    72             width = SDL_max(width, window->min_w);
    73 
    74             if (window->max_h > 0) {
    75                 height = SDL_min(height, window->max_h);
    76             }
    77             height = SDL_max(height, window->min_h);
    78         } else {
    79             return;
    80         }
    81     }
    82 
    83     WAYLAND_wl_egl_window_resize(wind->egl_window, width, height, 0, 0);
    84     region = wl_compositor_create_region(wind->waylandData->compositor);
    85     wl_region_add(region, 0, 0, width, height);
    86     wl_surface_set_opaque_region(wind->surface, region);
    87     wl_region_destroy(region);
    88 
    89     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
    90     window->w = width;
    91     window->h = height;
    92 }
    93 
    94 static void
    95 handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
    96 {
    97 }
    98 
    99 static const struct wl_shell_surface_listener shell_surface_listener_wl = {
   100     handle_ping_wl_shell_surface,
   101     handle_configure_wl_shell_surface,
   102     handle_popup_done_wl_shell_surface
   103 };
   104 
   105 
   106 
   107 
   108 static void
   109 handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
   110 {
   111     SDL_WindowData *wind = (SDL_WindowData *)data;
   112     SDL_Window *window = wind->sdlwindow;
   113     struct wl_region *region;
   114 
   115     wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
   116 
   117     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   118 
   119     region = wl_compositor_create_region(wind->waylandData->compositor);
   120     wl_region_add(region, 0, 0, window->w, window->h);
   121     wl_surface_set_opaque_region(wind->surface, region);
   122     wl_region_destroy(region);
   123     zxdg_surface_v6_ack_configure(zxdg, serial);
   124 }
   125 
   126 static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
   127     handle_configure_zxdg_shell_surface
   128 };
   129 
   130 
   131 static void
   132 handle_configure_zxdg_toplevel(void *data,
   133               struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
   134               int32_t width,
   135               int32_t height,
   136               struct wl_array *states)
   137 {
   138     SDL_WindowData *wind = (SDL_WindowData *)data;
   139     SDL_Window *window = wind->sdlwindow;
   140 
   141     /* wl_shell_surface spec states that this is a suggestion.
   142        Ignore if less than or greater than max/min size. */
   143 
   144     if (width == 0 || height == 0) {
   145         return;
   146     }
   147 
   148     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   149         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
   150             if (window->max_w > 0) {
   151                 width = SDL_min(width, window->max_w);
   152             } 
   153             width = SDL_max(width, window->min_w);
   154 
   155             if (window->max_h > 0) {
   156                 height = SDL_min(height, window->max_h);
   157             }
   158             height = SDL_max(height, window->min_h);
   159         } else {
   160             return;
   161         }
   162     }
   163 
   164     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
   165     window->w = width;
   166     window->h = height;
   167 }
   168 
   169 static void
   170 handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
   171 {
   172     SDL_WindowData *window = (SDL_WindowData *)data;
   173     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
   174 }
   175 
   176 static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
   177     handle_configure_zxdg_toplevel,
   178     handle_close_zxdg_toplevel
   179 };
   180 
   181 
   182 
   183 static void
   184 handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial)
   185 {
   186     SDL_WindowData *wind = (SDL_WindowData *)data;
   187     SDL_Window *window = wind->sdlwindow;
   188     struct wl_region *region;
   189 
   190     wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
   191 
   192     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   193 
   194     region = wl_compositor_create_region(wind->waylandData->compositor);
   195     wl_region_add(region, 0, 0, window->w, window->h);
   196     wl_surface_set_opaque_region(wind->surface, region);
   197     wl_region_destroy(region);
   198     xdg_surface_ack_configure(xdg, serial);
   199 }
   200 
   201 static const struct xdg_surface_listener shell_surface_listener_xdg = {
   202     handle_configure_xdg_shell_surface
   203 };
   204 
   205 
   206 static void
   207 handle_configure_xdg_toplevel(void *data,
   208               struct xdg_toplevel *xdg_toplevel,
   209               int32_t width,
   210               int32_t height,
   211               struct wl_array *states)
   212 {
   213     SDL_WindowData *wind = (SDL_WindowData *)data;
   214     SDL_Window *window = wind->sdlwindow;
   215 
   216     /* wl_shell_surface spec states that this is a suggestion.
   217        Ignore if less than or greater than max/min size. */
   218 
   219     if (width == 0 || height == 0) {
   220         return;
   221     }
   222 
   223     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   224         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
   225             if (window->max_w > 0) {
   226                 width = SDL_min(width, window->max_w);
   227             } 
   228             width = SDL_max(width, window->min_w);
   229 
   230             if (window->max_h > 0) {
   231                 height = SDL_min(height, window->max_h);
   232             }
   233             height = SDL_max(height, window->min_h);
   234         } else {
   235             return;
   236         }
   237     }
   238 
   239     if (width == window->w && height == window->h) {
   240         return;
   241     }
   242 
   243     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
   244     window->w = width;
   245     window->h = height;
   246 }
   247 
   248 static void
   249 handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
   250 {
   251     SDL_WindowData *window = (SDL_WindowData *)data;
   252     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
   253 }
   254 
   255 static const struct xdg_toplevel_listener toplevel_listener_xdg = {
   256     handle_configure_xdg_toplevel,
   257     handle_close_xdg_toplevel
   258 };
   259 
   260 
   261 
   262 
   263 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   264 static void
   265 handle_onscreen_visibility(void *data,
   266         struct qt_extended_surface *qt_extended_surface, int32_t visible)
   267 {
   268 }
   269 
   270 static void
   271 handle_set_generic_property(void *data,
   272         struct qt_extended_surface *qt_extended_surface, const char *name,
   273         struct wl_array *value)
   274 {
   275 }
   276 
   277 static void
   278 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
   279 {
   280     SDL_WindowData *window = (SDL_WindowData *)data;
   281     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
   282 }
   283 
   284 static const struct qt_extended_surface_listener extended_surface_listener = {
   285     handle_onscreen_visibility,
   286     handle_set_generic_property,
   287     handle_close,
   288 };
   289 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   290 
   291 SDL_bool
   292 Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   293 {
   294     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   295     const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
   296                             (((Uint32) info->version.minor) * 10000) +
   297                             (((Uint32) info->version.patch)));
   298 
   299     /* Before 2.0.6, it was possible to build an SDL with Wayland support
   300        (SDL_SysWMinfo will be large enough to hold Wayland info), but build
   301        your app against SDL headers that didn't have Wayland support
   302        (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
   303        to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
   304        overflow memory on the stack or heap. To protect against this, we've
   305        padded out the struct unconditionally in the headers and Wayland will
   306        just return an error for older apps using this function. Those apps
   307        will need to be recompiled against newer headers or not use Wayland,
   308        maybe by forcing SDL_VIDEODRIVER=x11. */
   309     if (version < 2000006) {
   310         info->subsystem = SDL_SYSWM_UNKNOWN;
   311         SDL_SetError("Version must be 2.0.6 or newer");
   312         return SDL_FALSE;
   313     }
   314 
   315     info->info.wl.display = data->waylandData->display;
   316     info->info.wl.surface = data->surface;
   317     info->info.wl.shell_surface = data->shell_surface.wl;
   318     info->subsystem = SDL_SYSWM_WAYLAND;
   319 
   320     return SDL_TRUE;
   321 }
   322 
   323 int
   324 Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   325 {
   326     return 0;  /* just succeed, the real work is done elsewhere. */
   327 }
   328 
   329 static void
   330 SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
   331 {
   332     const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   333     SDL_WindowData *wind = window->driverdata;
   334 
   335     if (viddata->shell.xdg) {
   336         if (output) {
   337             xdg_toplevel_set_fullscreen(wind->shell_surface.xdg.roleobj.toplevel, output);
   338         } else {
   339             xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel);
   340         }
   341     } else if (viddata->shell.zxdg) {
   342         if (output) {
   343             zxdg_toplevel_v6_set_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel, output);
   344         } else {
   345             zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel);
   346         }
   347     } else {
   348         if (output) {
   349             wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
   350                                             WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
   351                                             0, output);
   352         } else {
   353             wl_shell_surface_set_toplevel(wind->shell_surface.wl);
   354         }
   355     }
   356 
   357     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   358 }
   359 
   360 void Wayland_ShowWindow(_THIS, SDL_Window *window)
   361 {
   362     struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
   363     SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
   364 }
   365 
   366 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   367 static void SDLCALL
   368 QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
   369         const char *oldValue, const char *newValue)
   370 {
   371     struct qt_extended_surface *qt_extended_surface = userdata;
   372 
   373     if (name == NULL) {
   374         return;
   375     }
   376 
   377     if (strcmp(name, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION) == 0) {
   378         int32_t orientation = QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION;
   379 
   380         if (newValue != NULL) {
   381             if (strcmp(newValue, "portrait") == 0) {
   382                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION;
   383             } else if (strcmp(newValue, "landscape") == 0) {
   384                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION;
   385             } else if (strcmp(newValue, "inverted-portrait") == 0) {
   386                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION;
   387             } else if (strcmp(newValue, "inverted-landscape") == 0) {
   388                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION;
   389             }
   390         }
   391 
   392         qt_extended_surface_set_content_orientation(qt_extended_surface, orientation);
   393     } else if (strcmp(name, SDL_HINT_QTWAYLAND_WINDOW_FLAGS) == 0) {
   394         uint32_t flags = 0;
   395 
   396         if (newValue != NULL) {
   397             char *tmp = strdup(newValue);
   398             char *saveptr = NULL;
   399 
   400             char *flag = strtok_r(tmp, " ", &saveptr);
   401             while (flag) {
   402                 if (strcmp(flag, "OverridesSystemGestures") == 0) {
   403                     flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES;
   404                 } else if (strcmp(flag, "StaysOnTop") == 0) {
   405                     flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP;
   406                 } else if (strcmp(flag, "BypassWindowManager") == 0) {
   407                     // See https://github.com/qtproject/qtwayland/commit/fb4267103d
   408                     flags |= 4 /* QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER */;
   409                 }
   410 
   411                 flag = strtok_r(NULL, " ", &saveptr);
   412             }
   413 
   414             free(tmp);
   415         }
   416 
   417         qt_extended_surface_set_window_flags(qt_extended_surface, flags);
   418     }
   419 }
   420 
   421 static void QtExtendedSurface_Subscribe(struct qt_extended_surface *surface, const char *name)
   422 {
   423     SDL_AddHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
   424 }
   425 
   426 static void QtExtendedSurface_Unsubscribe(struct qt_extended_surface *surface, const char *name)
   427 {
   428     SDL_DelHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
   429 }
   430 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   431 
   432 void
   433 Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
   434                             SDL_VideoDisplay * _display, SDL_bool fullscreen)
   435 {
   436     struct wl_output *output = (struct wl_output *) _display->driverdata;
   437     SetFullscreen(_this, window, fullscreen ? output : NULL);
   438 }
   439 
   440 void
   441 Wayland_RestoreWindow(_THIS, SDL_Window * window)
   442 {
   443     SDL_WindowData *wind = window->driverdata;
   444     const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   445 
   446     if (viddata->shell.xdg) {
   447     } else if (viddata->shell.zxdg) {
   448     } else {
   449         wl_shell_surface_set_toplevel(wind->shell_surface.wl);
   450     }
   451 
   452     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   453 }
   454 
   455 void
   456 Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   457 {
   458     SDL_WindowData *wind = window->driverdata;
   459     const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   460     if ((viddata->kwin_server_decoration_manager) && (wind->kwin_server_decoration)) {
   461         const enum org_kde_kwin_server_decoration_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
   462         org_kde_kwin_server_decoration_request_mode(wind->kwin_server_decoration, mode);
   463     }
   464 }
   465 
   466 void
   467 Wayland_MaximizeWindow(_THIS, SDL_Window * window)
   468 {
   469     SDL_WindowData *wind = window->driverdata;
   470     SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   471 
   472     if (viddata->shell.xdg) {
   473         xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel);
   474     } else if (viddata->shell.zxdg) {
   475         zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel);
   476     } else {
   477         wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
   478     }
   479 
   480     WAYLAND_wl_display_flush( viddata->display );
   481 }
   482 
   483 int Wayland_CreateWindow(_THIS, SDL_Window *window)
   484 {
   485     SDL_WindowData *data;
   486     SDL_VideoData *c;
   487     struct wl_region *region;
   488 
   489     data = calloc(1, sizeof *data);
   490     if (data == NULL)
   491         return SDL_OutOfMemory();
   492 
   493     c = _this->driverdata;
   494     window->driverdata = data;
   495 
   496     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   497         SDL_GL_LoadLibrary(NULL);
   498         window->flags |= SDL_WINDOW_OPENGL;
   499     }
   500 
   501     if (window->x == SDL_WINDOWPOS_UNDEFINED) {
   502         window->x = 0;
   503     }
   504     if (window->y == SDL_WINDOWPOS_UNDEFINED) {
   505         window->y = 0;
   506     }
   507 
   508     data->waylandData = c;
   509     data->sdlwindow = window;
   510 
   511     data->surface =
   512         wl_compositor_create_surface(c->compositor);
   513     wl_surface_set_user_data(data->surface, data);
   514 
   515     if (c->shell.xdg) {
   516         data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface);
   517         /* !!! FIXME: add popup role */
   518         data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
   519         xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
   520         xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
   521     } else if (c->shell.zxdg) {
   522         data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
   523         /* !!! FIXME: add popup role */
   524         data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
   525         zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
   526         zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
   527     } else {
   528         data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
   529         wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
   530     }
   531 
   532 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   533     if (c->surface_extension) {
   534         data->extended_surface = qt_surface_extension_get_extended_surface(
   535                 c->surface_extension, data->surface);
   536 
   537         QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
   538         QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
   539     }
   540 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   541 
   542     data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
   543                                             window->w, window->h);
   544 
   545     /* Create the GLES window surface */
   546     data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
   547     
   548     if (data->egl_surface == EGL_NO_SURFACE) {
   549         return SDL_SetError("failed to create a window surface");
   550     }
   551 
   552     if (c->shell.xdg) {
   553         if (data->shell_surface.xdg.surface) {
   554             xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
   555             xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data);
   556         }
   557     } else if (c->shell.zxdg) {
   558         if (data->shell_surface.zxdg.surface) {
   559             zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
   560             zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
   561         }
   562     } else {
   563         if (data->shell_surface.wl) {
   564             wl_shell_surface_set_user_data(data->shell_surface.wl, data);
   565             wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
   566         }
   567     }
   568 
   569 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   570     if (data->extended_surface) {
   571         qt_extended_surface_set_user_data(data->extended_surface, data);
   572         qt_extended_surface_add_listener(data->extended_surface,
   573                                          &extended_surface_listener, data);
   574     }
   575 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   576 
   577     if (c->kwin_server_decoration_manager) {
   578         data->kwin_server_decoration = org_kde_kwin_server_decoration_manager_create(c->kwin_server_decoration_manager, data->surface);
   579         if (data->kwin_server_decoration) {
   580             const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
   581             const enum org_kde_kwin_server_decoration_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
   582             org_kde_kwin_server_decoration_request_mode(data->kwin_server_decoration, mode);
   583         }
   584     }
   585 
   586     region = wl_compositor_create_region(c->compositor);
   587     wl_region_add(region, 0, 0, window->w, window->h);
   588     wl_surface_set_opaque_region(data->surface, region);
   589     wl_region_destroy(region);
   590 
   591     if (c->relative_mouse_mode) {
   592         Wayland_input_lock_pointer(c->input);
   593     }
   594 
   595     wl_surface_commit(data->surface);
   596     WAYLAND_wl_display_flush(c->display);
   597 
   598     /* we have to wait until the surface gets a "configure" event, or
   599        use of this surface will fail. This is a new rule for xdg_shell. */
   600     if (c->shell.xdg) {
   601         if (data->shell_surface.xdg.surface) {
   602             while (!data->shell_surface.xdg.initial_configure_seen) {
   603                 WAYLAND_wl_display_flush(c->display);
   604                 WAYLAND_wl_display_dispatch(c->display);
   605             }
   606         }
   607     } else if (c->shell.zxdg) {
   608         if (data->shell_surface.zxdg.surface) {
   609             while (!data->shell_surface.zxdg.initial_configure_seen) {
   610                 WAYLAND_wl_display_flush(c->display);
   611                 WAYLAND_wl_display_dispatch(c->display);
   612             }
   613         }
   614     }
   615 
   616     return 0;
   617 }
   618 
   619 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
   620 {
   621     SDL_VideoData *data = _this->driverdata;
   622     SDL_WindowData *wind = window->driverdata;
   623     struct wl_region *region;
   624 
   625     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   626 
   627     region =wl_compositor_create_region(data->compositor);
   628     wl_region_add(region, 0, 0, window->w, window->h);
   629     wl_surface_set_opaque_region(wind->surface, region);
   630     wl_region_destroy(region);
   631 }
   632 
   633 void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
   634 {
   635     SDL_WindowData *wind = window->driverdata;
   636     SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   637     
   638     if (window->title != NULL) {
   639         if (viddata->shell.xdg) {
   640             xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, window->title);
   641         } else if (viddata->shell.zxdg) {
   642             zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title);
   643         } else {
   644             wl_shell_surface_set_title(wind->shell_surface.wl, window->title);
   645         }
   646     }
   647 
   648     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   649 }
   650 
   651 void Wayland_DestroyWindow(_THIS, SDL_Window *window)
   652 {
   653     SDL_VideoData *data = _this->driverdata;
   654     SDL_WindowData *wind = window->driverdata;
   655 
   656     if (data) {
   657         SDL_EGL_DestroySurface(_this, wind->egl_surface);
   658         WAYLAND_wl_egl_window_destroy(wind->egl_window);
   659 
   660         if (wind->kwin_server_decoration) {
   661             org_kde_kwin_server_decoration_release(wind->kwin_server_decoration);
   662         }
   663 
   664         if (data->shell.xdg) {
   665             if (wind->shell_surface.xdg.roleobj.toplevel) {
   666                 xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
   667             }
   668             if (wind->shell_surface.zxdg.surface) {
   669                 xdg_surface_destroy(wind->shell_surface.xdg.surface);
   670             }
   671         } else if (data->shell.zxdg) {
   672             if (wind->shell_surface.zxdg.roleobj.toplevel) {
   673                 zxdg_toplevel_v6_destroy(wind->shell_surface.zxdg.roleobj.toplevel);
   674             }
   675             if (wind->shell_surface.zxdg.surface) {
   676                 zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface);
   677             }
   678         } else {
   679             if (wind->shell_surface.wl) {
   680                 wl_shell_surface_destroy(wind->shell_surface.wl);
   681             }
   682         }
   683 
   684 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   685         if (wind->extended_surface) {
   686             QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
   687             QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
   688             qt_extended_surface_destroy(wind->extended_surface);
   689         }
   690 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   691         wl_surface_destroy(wind->surface);
   692 
   693         SDL_free(wind);
   694         WAYLAND_wl_display_flush(data->display);
   695     }
   696     window->driverdata = NULL;
   697 }
   698 
   699 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
   700 
   701 /* vi: set ts=4 sw=4 expandtab: */