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