src/video/wayland/SDL_waylandwindow.c
author Bastien Nocera <hadess@hadess.net>
Thu, 01 Sep 2016 01:22:58 -0700
changeset 10302 729eff9ee77a
parent 9998 f67cf37e9cd4
child 10304 ee83e0b4a36f
permissions -rw-r--r--
Wayland: Set "class" for each window we create
This will be used by Wayland compositors to match the application ID and
.desktop file to the SDL window(s).

Applications can set the SDL_VIDEO_WAYLAND_WMCLASS environemnt variable
early in the process to override using the binary name as a fallback.

Note that we also support the SDL_VIDEO_X11_WMCLASS in the Wayland
backend so that if a program correctly associated the desktop file with
the window under X11, only a newer SDL would be needed for it to work
under Wayland.

https://bugzilla.libsdl.org/show_bug.cgi?id=3376
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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_waylandwindow.h"
    30 #include "SDL_waylandvideo.h"
    31 #include "SDL_waylandtouch.h"
    32 #include "SDL_waylanddyn.h"
    33 
    34 static void
    35 handle_ping(void *data, struct wl_shell_surface *shell_surface,
    36             uint32_t serial)
    37 {
    38     wl_shell_surface_pong(shell_surface, serial);
    39 }
    40 
    41 static void
    42 handle_configure(void *data, struct wl_shell_surface *shell_surface,
    43                  uint32_t edges, int32_t width, int32_t height)
    44 {
    45     SDL_WindowData *wind = (SDL_WindowData *)data;
    46     SDL_Window *window = wind->sdlwindow;
    47     struct wl_region *region;
    48 
    49     window->w = width;
    50     window->h = height;
    51     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
    52 
    53     region = wl_compositor_create_region(wind->waylandData->compositor);
    54     wl_region_add(region, 0, 0, window->w, window->h);
    55     wl_surface_set_opaque_region(wind->surface, region);
    56     wl_region_destroy(region);
    57     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
    58 }
    59 
    60 static void
    61 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
    62 {
    63 }
    64 
    65 static const struct wl_shell_surface_listener shell_surface_listener = {
    66     handle_ping,
    67     handle_configure,
    68     handle_popup_done
    69 };
    70 
    71 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    72 static void
    73 handle_onscreen_visibility(void *data,
    74         struct qt_extended_surface *qt_extended_surface, int32_t visible)
    75 {
    76 }
    77 
    78 static void
    79 handle_set_generic_property(void *data,
    80         struct qt_extended_surface *qt_extended_surface, const char *name,
    81         struct wl_array *value)
    82 {
    83 }
    84 
    85 static void
    86 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
    87 {
    88     SDL_WindowData *window = (SDL_WindowData *)data;
    89     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
    90 }
    91 
    92 static const struct qt_extended_surface_listener extended_surface_listener = {
    93     handle_onscreen_visibility,
    94     handle_set_generic_property,
    95     handle_close,
    96 };
    97 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
    98 
    99 SDL_bool
   100 Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   101 {
   102     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   103 
   104     info->info.wl.display = data->waylandData->display;
   105     info->info.wl.surface = data->surface;
   106     info->info.wl.shell_surface = data->shell_surface;
   107     info->subsystem = SDL_SYSWM_WAYLAND;
   108 
   109     return SDL_TRUE;
   110 }
   111 
   112 int
   113 Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   114 {
   115     return 0;  /* just succeed, the real work is done elsewhere. */
   116 }
   117 
   118 void Wayland_ShowWindow(_THIS, SDL_Window *window)
   119 {
   120     SDL_WindowData *wind = window->driverdata;
   121 
   122     if (window->flags & SDL_WINDOW_FULLSCREEN)
   123         wl_shell_surface_set_fullscreen(wind->shell_surface,
   124                                         WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
   125                                         0, (struct wl_output *)window->fullscreen_mode.driverdata);
   126     else
   127         wl_shell_surface_set_toplevel(wind->shell_surface);
   128 
   129     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   130 }
   131 
   132 void
   133 Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
   134                             SDL_VideoDisplay * _display, SDL_bool fullscreen)
   135 {
   136     SDL_WindowData *wind = window->driverdata;
   137 
   138     if (fullscreen)
   139         wl_shell_surface_set_fullscreen(wind->shell_surface,
   140                                         WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
   141                                         0, (struct wl_output *)_display->driverdata);
   142     else
   143         wl_shell_surface_set_toplevel(wind->shell_surface);
   144 
   145     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   146 }
   147 
   148 int Wayland_CreateWindow(_THIS, SDL_Window *window)
   149 {
   150     SDL_WindowData *data;
   151     SDL_VideoData *c;
   152     struct wl_region *region;
   153 
   154     data = calloc(1, sizeof *data);
   155     if (data == NULL)
   156         return SDL_OutOfMemory();
   157 
   158     c = _this->driverdata;
   159     window->driverdata = data;
   160 
   161     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   162         SDL_GL_LoadLibrary(NULL);
   163         window->flags |= SDL_WINDOW_OPENGL;
   164     }
   165 
   166     if (window->x == SDL_WINDOWPOS_UNDEFINED) {
   167         window->x = 0;
   168     }
   169     if (window->y == SDL_WINDOWPOS_UNDEFINED) {
   170         window->y = 0;
   171     }
   172 
   173     data->waylandData = c;
   174     data->sdlwindow = window;
   175 
   176     data->surface =
   177         wl_compositor_create_surface(c->compositor);
   178     wl_surface_set_user_data(data->surface, data);
   179     data->shell_surface = wl_shell_get_shell_surface(c->shell,
   180                                                      data->surface);
   181     wl_shell_surface_set_class (data->shell_surface, c->classname);
   182 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH    
   183     if (c->surface_extension) {
   184         data->extended_surface = qt_surface_extension_get_extended_surface(
   185                 c->surface_extension, data->surface);
   186     }
   187 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   188 
   189     data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
   190                                             window->w, window->h);
   191 
   192     /* Create the GLES window surface */
   193     data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
   194     
   195     if (data->egl_surface == EGL_NO_SURFACE) {
   196         return SDL_SetError("failed to create a window surface");
   197     }
   198 
   199     if (data->shell_surface) {
   200         wl_shell_surface_set_user_data(data->shell_surface, data);
   201         wl_shell_surface_add_listener(data->shell_surface,
   202                                       &shell_surface_listener, data);
   203     }
   204 
   205 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   206     if (data->extended_surface) {
   207         qt_extended_surface_set_user_data(data->extended_surface, data);
   208         qt_extended_surface_add_listener(data->extended_surface,
   209                                          &extended_surface_listener, data);
   210     }
   211 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   212 
   213     region = wl_compositor_create_region(c->compositor);
   214     wl_region_add(region, 0, 0, window->w, window->h);
   215     wl_surface_set_opaque_region(data->surface, region);
   216     wl_region_destroy(region);
   217 
   218     WAYLAND_wl_display_flush(c->display);
   219 
   220     return 0;
   221 }
   222 
   223 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
   224 {
   225     SDL_VideoData *data = _this->driverdata;
   226     SDL_WindowData *wind = window->driverdata;
   227     struct wl_region *region;
   228 
   229     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   230 
   231     region =wl_compositor_create_region(data->compositor);
   232     wl_region_add(region, 0, 0, window->w, window->h);
   233     wl_surface_set_opaque_region(wind->surface, region);
   234     wl_region_destroy(region);
   235 }
   236 
   237 void Wayland_DestroyWindow(_THIS, SDL_Window *window)
   238 {
   239     SDL_VideoData *data = _this->driverdata;
   240     SDL_WindowData *wind = window->driverdata;
   241 
   242     if (data) {
   243         SDL_EGL_DestroySurface(_this, wind->egl_surface);
   244         WAYLAND_wl_egl_window_destroy(wind->egl_window);
   245 
   246         if (wind->shell_surface)
   247             wl_shell_surface_destroy(wind->shell_surface);
   248 
   249 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   250         if (wind->extended_surface)
   251             qt_extended_surface_destroy(wind->extended_surface);
   252 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   253         wl_surface_destroy(wind->surface);
   254 
   255         SDL_free(wind);
   256         WAYLAND_wl_display_flush(data->display);
   257     }
   258     window->driverdata = NULL;
   259 }
   260 
   261 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
   262 
   263 /* vi: set ts=4 sw=4 expandtab: */