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