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