src/video/wayland/SDL_waylandwindow.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 15 Apr 2018 17:42:09 -0400
changeset 11944 295cf9910d75
parent 11848 2f157c1ca383
child 12033 bc702c5a7c3a
permissions -rw-r--r--
wayland: zxdg_shell_v6 needs a configure event before using a surface at all.

Fixes Bugzilla #4109.
Fixes Bugzilla #4119.
     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-unstable-v6-client-protocol.h"
    37 
    38 /* On modern desktops, we probably will use the xdg-shell protocol instead
    39    of wl_shell, but wl_shell might be useful on older Wayland installs that
    40    don't have the newer protocol, or embedded things that don't have a full
    41    window manager. */
    42 
    43 static void
    44 handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
    45             uint32_t serial)
    46 {
    47     wl_shell_surface_pong(shell_surface, serial);
    48 }
    49 
    50 static void
    51 handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
    52                  uint32_t edges, int32_t width, int32_t height)
    53 {
    54     SDL_WindowData *wind = (SDL_WindowData *)data;
    55     SDL_Window *window = wind->sdlwindow;
    56     struct wl_region *region;
    57 
    58     /* wl_shell_surface spec states that this is a suggestion.
    59        Ignore if less than or greater than max/min size. */
    60 
    61     if (width == 0 || height == 0) {
    62         return;
    63     }
    64 
    65     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
    66         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
    67             if (window->max_w > 0) {
    68                 width = SDL_min(width, window->max_w);
    69             } 
    70             width = SDL_max(width, window->min_w);
    71 
    72             if (window->max_h > 0) {
    73                 height = SDL_min(height, window->max_h);
    74             }
    75             height = SDL_max(height, window->min_h);
    76         } else {
    77             return;
    78         }
    79     }
    80 
    81     if (width == window->w && height == window->h) {
    82         return;
    83     }
    84 
    85     window->w = width;
    86     window->h = height;
    87     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
    88 
    89     region = wl_compositor_create_region(wind->waylandData->compositor);
    90     wl_region_add(region, 0, 0, window->w, window->h);
    91     wl_surface_set_opaque_region(wind->surface, region);
    92     wl_region_destroy(region);
    93     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
    94 }
    95 
    96 static void
    97 handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
    98 {
    99 }
   100 
   101 static const struct wl_shell_surface_listener shell_surface_listener_wl = {
   102     handle_ping_wl_shell_surface,
   103     handle_configure_wl_shell_surface,
   104     handle_popup_done_wl_shell_surface
   105 };
   106 
   107 
   108 
   109 
   110 static void
   111 handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
   112 {
   113     SDL_WindowData *wind = (SDL_WindowData *)data;
   114     SDL_Window *window = wind->sdlwindow;
   115     struct wl_region *region;
   116 
   117     wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
   118 
   119     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   120 
   121     region = wl_compositor_create_region(wind->waylandData->compositor);
   122     wl_region_add(region, 0, 0, window->w, window->h);
   123     wl_surface_set_opaque_region(wind->surface, region);
   124     wl_region_destroy(region);
   125     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
   126     zxdg_surface_v6_ack_configure(zxdg, serial);
   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     /* wl_shell_surface spec states that this is a suggestion.
   145        Ignore if less than or greater than max/min size. */
   146 
   147     if (width == 0 || height == 0) {
   148         return;
   149     }
   150 
   151     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   152         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
   153             if (window->max_w > 0) {
   154                 width = SDL_min(width, window->max_w);
   155             } 
   156             width = SDL_max(width, window->min_w);
   157 
   158             if (window->max_h > 0) {
   159                 height = SDL_min(height, window->max_h);
   160             }
   161             height = SDL_max(height, window->min_h);
   162         } else {
   163             return;
   164         }
   165     }
   166 
   167     if (width == window->w && height == window->h) {
   168         return;
   169     }
   170 
   171     window->w = width;
   172     window->h = height;
   173 }
   174 
   175 static void
   176 handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
   177 {
   178     SDL_WindowData *window = (SDL_WindowData *)data;
   179     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
   180 }
   181 
   182 static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
   183     handle_configure_zxdg_toplevel,
   184     handle_close_zxdg_toplevel
   185 };
   186 
   187 
   188 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   189 static void
   190 handle_onscreen_visibility(void *data,
   191         struct qt_extended_surface *qt_extended_surface, int32_t visible)
   192 {
   193 }
   194 
   195 static void
   196 handle_set_generic_property(void *data,
   197         struct qt_extended_surface *qt_extended_surface, const char *name,
   198         struct wl_array *value)
   199 {
   200 }
   201 
   202 static void
   203 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
   204 {
   205     SDL_WindowData *window = (SDL_WindowData *)data;
   206     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
   207 }
   208 
   209 static const struct qt_extended_surface_listener extended_surface_listener = {
   210     handle_onscreen_visibility,
   211     handle_set_generic_property,
   212     handle_close,
   213 };
   214 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   215 
   216 SDL_bool
   217 Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   218 {
   219     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   220     const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
   221                             (((Uint32) info->version.minor) * 10000) +
   222                             (((Uint32) info->version.patch)));
   223 
   224     /* Before 2.0.6, it was possible to build an SDL with Wayland support
   225        (SDL_SysWMinfo will be large enough to hold Wayland info), but build
   226        your app against SDL headers that didn't have Wayland support
   227        (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
   228        to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
   229        overflow memory on the stack or heap. To protect against this, we've
   230        padded out the struct unconditionally in the headers and Wayland will
   231        just return an error for older apps using this function. Those apps
   232        will need to be recompiled against newer headers or not use Wayland,
   233        maybe by forcing SDL_VIDEODRIVER=x11. */
   234     if (version < 2000006) {
   235         info->subsystem = SDL_SYSWM_UNKNOWN;
   236         SDL_SetError("Version must be 2.0.6 or newer");
   237         return SDL_FALSE;
   238     }
   239 
   240     info->info.wl.display = data->waylandData->display;
   241     info->info.wl.surface = data->surface;
   242     info->info.wl.shell_surface = data->shell_surface.wl;
   243     info->subsystem = SDL_SYSWM_WAYLAND;
   244 
   245     return SDL_TRUE;
   246 }
   247 
   248 int
   249 Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   250 {
   251     return 0;  /* just succeed, the real work is done elsewhere. */
   252 }
   253 
   254 static void
   255 SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
   256 {
   257     const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   258     SDL_WindowData *wind = window->driverdata;
   259 
   260     if (viddata->shell.zxdg) {
   261         if (output) {
   262             zxdg_toplevel_v6_set_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel, output);
   263         } else {
   264             zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel);
   265         }
   266     } else {
   267         if (output) {
   268             wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
   269                                             WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
   270                                             0, output);
   271         } else {
   272             wl_shell_surface_set_toplevel(wind->shell_surface.wl);
   273         }
   274     }
   275 
   276     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   277 }
   278 
   279 void Wayland_ShowWindow(_THIS, SDL_Window *window)
   280 {
   281     struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
   282     SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
   283 }
   284 
   285 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   286 static void SDLCALL
   287 QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
   288         const char *oldValue, const char *newValue)
   289 {
   290     struct qt_extended_surface *qt_extended_surface = userdata;
   291 
   292     if (name == NULL) {
   293         return;
   294     }
   295 
   296     if (strcmp(name, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION) == 0) {
   297         int32_t orientation = QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION;
   298 
   299         if (newValue != NULL) {
   300             if (strcmp(newValue, "portrait") == 0) {
   301                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION;
   302             } else if (strcmp(newValue, "landscape") == 0) {
   303                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION;
   304             } else if (strcmp(newValue, "inverted-portrait") == 0) {
   305                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION;
   306             } else if (strcmp(newValue, "inverted-landscape") == 0) {
   307                 orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION;
   308             }
   309         }
   310 
   311         qt_extended_surface_set_content_orientation(qt_extended_surface, orientation);
   312     } else if (strcmp(name, SDL_HINT_QTWAYLAND_WINDOW_FLAGS) == 0) {
   313         uint32_t flags = 0;
   314 
   315         if (newValue != NULL) {
   316             char *tmp = strdup(newValue);
   317             char *saveptr = NULL;
   318 
   319             char *flag = strtok_r(tmp, " ", &saveptr);
   320             while (flag) {
   321                 if (strcmp(flag, "OverridesSystemGestures") == 0) {
   322                     flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES;
   323                 } else if (strcmp(flag, "StaysOnTop") == 0) {
   324                     flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP;
   325                 } else if (strcmp(flag, "BypassWindowManager") == 0) {
   326                     // See https://github.com/qtproject/qtwayland/commit/fb4267103d
   327                     flags |= 4 /* QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER */;
   328                 }
   329 
   330                 flag = strtok_r(NULL, " ", &saveptr);
   331             }
   332 
   333             free(tmp);
   334         }
   335 
   336         qt_extended_surface_set_window_flags(qt_extended_surface, flags);
   337     }
   338 }
   339 
   340 static void QtExtendedSurface_Subscribe(struct qt_extended_surface *surface, const char *name)
   341 {
   342     SDL_AddHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
   343 }
   344 
   345 static void QtExtendedSurface_Unsubscribe(struct qt_extended_surface *surface, const char *name)
   346 {
   347     SDL_DelHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
   348 }
   349 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   350 
   351 void
   352 Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
   353                             SDL_VideoDisplay * _display, SDL_bool fullscreen)
   354 {
   355     struct wl_output *output = (struct wl_output *) _display->driverdata;
   356     SetFullscreen(_this, window, fullscreen ? output : NULL);
   357 }
   358 
   359 void
   360 Wayland_RestoreWindow(_THIS, SDL_Window * window)
   361 {
   362     SDL_WindowData *wind = window->driverdata;
   363     const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   364 
   365     if (viddata->shell.zxdg) {
   366     } else {
   367         wl_shell_surface_set_toplevel(wind->shell_surface.wl);
   368     }
   369 
   370     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   371 }
   372 
   373 void
   374 Wayland_MaximizeWindow(_THIS, SDL_Window * window)
   375 {
   376     SDL_WindowData *wind = window->driverdata;
   377     SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   378 
   379     if (viddata->shell.zxdg) {
   380         zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel);
   381     } else {
   382         wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
   383     }
   384 
   385     WAYLAND_wl_display_flush( viddata->display );
   386 }
   387 
   388 int Wayland_CreateWindow(_THIS, SDL_Window *window)
   389 {
   390     SDL_WindowData *data;
   391     SDL_VideoData *c;
   392     struct wl_region *region;
   393 
   394     data = calloc(1, sizeof *data);
   395     if (data == NULL)
   396         return SDL_OutOfMemory();
   397 
   398     c = _this->driverdata;
   399     window->driverdata = data;
   400 
   401     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   402         SDL_GL_LoadLibrary(NULL);
   403         window->flags |= SDL_WINDOW_OPENGL;
   404     }
   405 
   406     if (window->x == SDL_WINDOWPOS_UNDEFINED) {
   407         window->x = 0;
   408     }
   409     if (window->y == SDL_WINDOWPOS_UNDEFINED) {
   410         window->y = 0;
   411     }
   412 
   413     data->waylandData = c;
   414     data->sdlwindow = window;
   415 
   416     data->surface =
   417         wl_compositor_create_surface(c->compositor);
   418     wl_surface_set_user_data(data->surface, data);
   419 
   420     if (c->shell.zxdg) {
   421         data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
   422         /* !!! FIXME: add popup role */
   423         data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
   424         zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
   425         zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
   426     } else {
   427         data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
   428         wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
   429     }
   430 
   431 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   432     if (c->surface_extension) {
   433         data->extended_surface = qt_surface_extension_get_extended_surface(
   434                 c->surface_extension, data->surface);
   435 
   436         QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
   437         QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
   438     }
   439 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   440 
   441     data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
   442                                             window->w, window->h);
   443 
   444     /* Create the GLES window surface */
   445     data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
   446     
   447     if (data->egl_surface == EGL_NO_SURFACE) {
   448         return SDL_SetError("failed to create a window surface");
   449     }
   450 
   451     if (c->shell.zxdg) {
   452         if (data->shell_surface.zxdg.surface) {
   453             zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
   454             zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
   455         }
   456     } else {
   457         if (data->shell_surface.wl) {
   458             wl_shell_surface_set_user_data(data->shell_surface.wl, data);
   459             wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
   460         }
   461     }
   462 
   463 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   464     if (data->extended_surface) {
   465         qt_extended_surface_set_user_data(data->extended_surface, data);
   466         qt_extended_surface_add_listener(data->extended_surface,
   467                                          &extended_surface_listener, data);
   468     }
   469 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   470 
   471     region = wl_compositor_create_region(c->compositor);
   472     wl_region_add(region, 0, 0, window->w, window->h);
   473     wl_surface_set_opaque_region(data->surface, region);
   474     wl_region_destroy(region);
   475 
   476     if (c->relative_mouse_mode) {
   477         Wayland_input_lock_pointer(c->input);
   478     }
   479 
   480     wl_surface_commit(data->surface);
   481     WAYLAND_wl_display_flush(c->display);
   482 
   483     /* we have to wait until the surface gets a "configure" event, or
   484        use of this surface will fail. This is a new rule for xdg_shell. */
   485     if (c->shell.zxdg) {
   486         if (data->shell_surface.zxdg.surface) {
   487             while (!data->shell_surface.zxdg.initial_configure_seen) {
   488                 WAYLAND_wl_display_flush(c->display);
   489                 WAYLAND_wl_display_dispatch(c->display);
   490             }
   491         }
   492     }
   493 
   494     return 0;
   495 }
   496 
   497 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
   498 {
   499     SDL_VideoData *data = _this->driverdata;
   500     SDL_WindowData *wind = window->driverdata;
   501     struct wl_region *region;
   502 
   503     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   504 
   505     region =wl_compositor_create_region(data->compositor);
   506     wl_region_add(region, 0, 0, window->w, window->h);
   507     wl_surface_set_opaque_region(wind->surface, region);
   508     wl_region_destroy(region);
   509 }
   510 
   511 void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
   512 {
   513     SDL_WindowData *wind = window->driverdata;
   514     SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   515     
   516     if (window->title != NULL) {
   517         if (viddata->shell.zxdg) {
   518             zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title);
   519         } else {
   520             wl_shell_surface_set_title(wind->shell_surface.wl, window->title);
   521         }
   522     }
   523 
   524     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   525 }
   526 
   527 void Wayland_DestroyWindow(_THIS, SDL_Window *window)
   528 {
   529     SDL_VideoData *data = _this->driverdata;
   530     SDL_WindowData *wind = window->driverdata;
   531 
   532     if (data) {
   533         SDL_EGL_DestroySurface(_this, wind->egl_surface);
   534         WAYLAND_wl_egl_window_destroy(wind->egl_window);
   535 
   536         if (data->shell.zxdg) {
   537             if (wind->shell_surface.zxdg.roleobj.toplevel) {
   538                 zxdg_toplevel_v6_destroy(wind->shell_surface.zxdg.roleobj.toplevel);
   539             }
   540             if (wind->shell_surface.zxdg.surface) {
   541                 zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface);
   542             }
   543         } else {
   544             if (wind->shell_surface.wl) {
   545                 wl_shell_surface_destroy(wind->shell_surface.wl);
   546             }
   547         }
   548 
   549 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   550         if (wind->extended_surface) {
   551             QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
   552             QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
   553             qt_extended_surface_destroy(wind->extended_surface);
   554         }
   555 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   556         wl_surface_destroy(wind->surface);
   557 
   558         SDL_free(wind);
   559         WAYLAND_wl_display_flush(data->display);
   560     }
   561     window->driverdata = NULL;
   562 }
   563 
   564 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
   565 
   566 /* vi: set ts=4 sw=4 expandtab: */