src/video/wayland/SDL_waylandwindow.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 01 Sep 2016 01:26:56 -0700
changeset 10304 ee83e0b4a36f
parent 10302 729eff9ee77a
child 10492 786e10ab72d8
permissions -rw-r--r--
wayland: Add support for relative mouse mode, by Jonas Ã…dahl <jadahl@gmail.com>

Generate the C protocol files from the protocol XML files installed by
wayland-protocols, and use them to implement support for relative pointer
motions and pointer locking.

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