src/video/wayland/SDL_waylandvideo.c
author Arne Janbu <arnej@arnej.de>
Sat, 10 Jan 2015 13:47:37 +0100
changeset 9362 dfd8202eb9a7
parent 8160 71639d445b59
child 9467 975453c4e217
permissions -rw-r--r--
Fix build on Linux when wayland is enabled

Bug: https://bugzilla.libsdl.org/show_bug.cgi?id=2838
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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
    25 
    26 #include "SDL_video.h"
    27 #include "SDL_mouse.h"
    28 #include "SDL_stdinc.h"
    29 #include "../../events/SDL_events_c.h"
    30 
    31 #include "SDL_waylandvideo.h"
    32 #include "SDL_waylandevents_c.h"
    33 #include "SDL_waylandwindow.h"
    34 #include "SDL_waylandopengles.h"
    35 #include "SDL_waylandmouse.h"
    36 #include "SDL_waylandtouch.h"
    37 
    38 #include <fcntl.h>
    39 #include <xkbcommon/xkbcommon.h>
    40 
    41 #include "SDL_waylanddyn.h"
    42 #include <wayland-util.h>
    43 
    44 #define WAYLANDVID_DRIVER_NAME "wayland"
    45 
    46 struct wayland_mode {
    47     SDL_DisplayMode mode;
    48     struct wl_list link;
    49 };
    50 
    51 /* Initialization/Query functions */
    52 static int
    53 Wayland_VideoInit(_THIS);
    54 
    55 static void
    56 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
    57 static int
    58 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
    59 
    60 static void
    61 Wayland_VideoQuit(_THIS);
    62 
    63 /* Wayland driver bootstrap functions */
    64 static int
    65 Wayland_Available(void)
    66 {
    67     struct wl_display *display = NULL;
    68     if (SDL_WAYLAND_LoadSymbols()) {
    69         display = WAYLAND_wl_display_connect(NULL);
    70         if (display != NULL) {
    71             WAYLAND_wl_display_disconnect(display);
    72         }
    73         SDL_WAYLAND_UnloadSymbols();
    74     }
    75 
    76     return (display != NULL);
    77 }
    78 
    79 static void
    80 Wayland_DeleteDevice(SDL_VideoDevice *device)
    81 {
    82     SDL_free(device);
    83     SDL_WAYLAND_UnloadSymbols();
    84 }
    85 
    86 static SDL_VideoDevice *
    87 Wayland_CreateDevice(int devindex)
    88 {
    89     SDL_VideoDevice *device;
    90     
    91     if (!SDL_WAYLAND_LoadSymbols()) {
    92         return NULL;
    93     }
    94 
    95     /* Initialize all variables that we clean on shutdown */
    96     device = SDL_calloc(1, sizeof(SDL_VideoDevice));
    97     if (!device) {
    98         SDL_WAYLAND_UnloadSymbols();
    99         SDL_OutOfMemory();
   100         return NULL;
   101     }
   102 
   103     /* Set the function pointers */
   104     device->VideoInit = Wayland_VideoInit;
   105     device->VideoQuit = Wayland_VideoQuit;
   106     device->SetDisplayMode = Wayland_SetDisplayMode;
   107     device->GetDisplayModes = Wayland_GetDisplayModes;
   108     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
   109 
   110     device->PumpEvents = Wayland_PumpEvents;
   111 
   112     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
   113     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
   114     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
   115     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
   116     device->GL_CreateContext = Wayland_GLES_CreateContext;
   117     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
   118     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
   119     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
   120     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
   121 
   122     device->CreateWindow = Wayland_CreateWindow;
   123     device->ShowWindow = Wayland_ShowWindow;
   124     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
   125     device->SetWindowSize = Wayland_SetWindowSize;
   126     device->DestroyWindow = Wayland_DestroyWindow;
   127 
   128     device->free = Wayland_DeleteDevice;
   129 
   130     return device;
   131 }
   132 
   133 VideoBootStrap Wayland_bootstrap = {
   134     WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
   135     Wayland_Available, Wayland_CreateDevice
   136 };
   137 
   138 static void
   139 wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
   140 {
   141     struct wayland_mode *mode;
   142 
   143     /* Check for duplicate mode */
   144     wl_list_for_each(mode, &d->modes_list, link)
   145         if (mode->mode.w == m.w && mode->mode.h == m.h &&
   146 	    mode->mode.refresh_rate == m.refresh_rate)
   147 	    return;
   148 
   149     /* Add new mode to the list */
   150     mode = (struct wayland_mode *) SDL_calloc(1, sizeof *mode);
   151 
   152     if (!mode)
   153 	return;
   154 
   155     mode->mode = m;
   156     WAYLAND_wl_list_insert(&d->modes_list, &mode->link);
   157 }
   158 
   159 static void
   160 display_handle_geometry(void *data,
   161                         struct wl_output *output,
   162                         int x, int y,
   163                         int physical_width,
   164                         int physical_height,
   165                         int subpixel,
   166                         const char *make,
   167                         const char *model,
   168                         int transform)
   169 
   170 {
   171     SDL_VideoData *d = data;
   172 
   173     d->screen_allocation.x = x;
   174     d->screen_allocation.y = y;
   175 }
   176 
   177 static void
   178 display_handle_mode(void *data,
   179                     struct wl_output *wl_output,
   180                     uint32_t flags,
   181                     int width,
   182                     int height,
   183                     int refresh)
   184 {
   185     SDL_VideoData *d = data;
   186     SDL_DisplayMode mode;
   187 
   188     SDL_zero(mode);
   189     mode.w = width;
   190     mode.h = height;
   191     mode.refresh_rate = refresh / 1000;
   192 
   193     wayland_add_mode(d, mode);
   194 
   195     if (flags & WL_OUTPUT_MODE_CURRENT) {
   196         d->screen_allocation.width = width;
   197         d->screen_allocation.height = height;
   198     }
   199 }
   200 
   201 static const struct wl_output_listener output_listener = {
   202     display_handle_geometry,
   203     display_handle_mode
   204 };
   205 
   206 static void
   207 shm_handle_format(void *data,
   208                   struct wl_shm *shm,
   209                   uint32_t format)
   210 {
   211     SDL_VideoData *d = data;
   212 
   213     d->shm_formats |= (1 << format);
   214 }
   215 
   216 static const struct wl_shm_listener shm_listener = {
   217     shm_handle_format
   218 };
   219 
   220 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   221 static void
   222 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
   223         int32_t show_is_fullscreen)
   224 {
   225 }
   226 
   227 static void
   228 windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
   229 {
   230     SDL_SendQuit();
   231 }
   232 
   233 static const struct qt_windowmanager_listener windowmanager_listener = {
   234     windowmanager_hints,
   235     windowmanager_quit,
   236 };
   237 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   238 
   239 static void
   240 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   241 					const char *interface, uint32_t version)
   242 {
   243     SDL_VideoData *d = data;
   244     
   245     if (strcmp(interface, "wl_compositor") == 0) {
   246         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   247     } else if (strcmp(interface, "wl_output") == 0) {
   248         d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
   249         wl_output_add_listener(d->output, &output_listener, d);
   250     } else if (strcmp(interface, "wl_seat") == 0) {
   251         Wayland_display_add_input(d, id);
   252     } else if (strcmp(interface, "wl_shell") == 0) {
   253         d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
   254     } else if (strcmp(interface, "wl_shm") == 0) {
   255         d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
   256         d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
   257         d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
   258         wl_shm_add_listener(d->shm, &shm_listener, d);
   259     
   260 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   261     } else if (strcmp(interface, "qt_touch_extension") == 0) {
   262         Wayland_touch_create(d, id);
   263     } else if (strcmp(interface, "qt_surface_extension") == 0) {
   264         d->surface_extension = wl_registry_bind(registry, id,
   265                 &qt_surface_extension_interface, 1);
   266     } else if (strcmp(interface, "qt_windowmanager") == 0) {
   267         d->windowmanager = wl_registry_bind(registry, id,
   268                 &qt_windowmanager_interface, 1);
   269         qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
   270 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   271     }
   272 }
   273 
   274 static const struct wl_registry_listener registry_listener = {
   275 	display_handle_global
   276 };
   277 
   278 int
   279 Wayland_VideoInit(_THIS)
   280 {
   281     SDL_VideoData *data;
   282     SDL_VideoDisplay display;
   283     SDL_DisplayMode mode;
   284     int i;
   285     
   286     data = malloc(sizeof *data);
   287     if (data == NULL)
   288         return 0;
   289     memset(data, 0, sizeof *data);
   290 
   291     _this->driverdata = data;
   292 
   293     WAYLAND_wl_list_init(&data->modes_list);
   294     
   295     data->display = WAYLAND_wl_display_connect(NULL);
   296     if (data->display == NULL) {
   297         SDL_SetError("Failed to connect to a Wayland display");
   298         return 0;
   299     }
   300 
   301     data->registry = wl_display_get_registry(data->display);
   302    
   303     if ( data->registry == NULL) {
   304         SDL_SetError("Failed to get the Wayland registry");
   305         return 0;
   306     }
   307     
   308     wl_registry_add_listener(data->registry, &registry_listener, data);
   309 
   310     for (i=0; i < 100; i++) {
   311         if (data->screen_allocation.width != 0 || WAYLAND_wl_display_get_error(data->display) != 0) {
   312             break;
   313         }
   314         WAYLAND_wl_display_dispatch(data->display);
   315     }
   316     
   317     if (data->screen_allocation.width == 0) {
   318         SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display));
   319         return 0;
   320     }
   321 
   322     data->xkb_context = WAYLAND_xkb_context_new(0);
   323     if (!data->xkb_context) {
   324         SDL_SetError("Failed to create XKB context");
   325         return 0;
   326     }
   327 
   328     /* Use a fake 32-bpp desktop mode */
   329     mode.format = SDL_PIXELFORMAT_RGB888;
   330     mode.w = data->screen_allocation.width;
   331     mode.h = data->screen_allocation.height;
   332     mode.refresh_rate = 0;
   333     mode.driverdata = NULL;
   334     wayland_add_mode(data, mode);
   335     SDL_zero(display);
   336     display.desktop_mode = mode;
   337     display.current_mode = mode;
   338     display.driverdata = NULL;
   339     SDL_AddVideoDisplay(&display);
   340 
   341     Wayland_InitMouse ();
   342 
   343     WAYLAND_wl_display_flush(data->display);
   344 
   345     return 0;
   346 }
   347 
   348 static void
   349 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   350 {
   351     SDL_VideoData *data = _this->driverdata;
   352     SDL_DisplayMode mode;
   353     struct wayland_mode *m;
   354 
   355     Wayland_PumpEvents(_this);
   356 
   357     wl_list_for_each(m, &data->modes_list, link) {
   358         m->mode.format = SDL_PIXELFORMAT_RGB888;
   359         SDL_AddDisplayMode(sdl_display, &m->mode);
   360         m->mode.format = SDL_PIXELFORMAT_RGBA8888;
   361         SDL_AddDisplayMode(sdl_display, &m->mode);
   362     }
   363 
   364     mode.w = data->screen_allocation.width;
   365     mode.h = data->screen_allocation.height;
   366     mode.refresh_rate = 0;
   367     mode.driverdata = NULL;
   368 
   369     mode.format = SDL_PIXELFORMAT_RGB888;
   370     SDL_AddDisplayMode(sdl_display, &mode);
   371     mode.format = SDL_PIXELFORMAT_RGBA8888;
   372     SDL_AddDisplayMode(sdl_display, &mode);
   373 }
   374 
   375 static int
   376 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   377 {
   378     return 0;
   379 }
   380 
   381 void
   382 Wayland_VideoQuit(_THIS)
   383 {
   384     SDL_VideoData *data = _this->driverdata;
   385     struct wayland_mode *t, *m;
   386 
   387     Wayland_FiniMouse ();
   388 
   389     if (data->output)
   390         wl_output_destroy(data->output);
   391 
   392     Wayland_display_destroy_input(data);
   393 
   394     if (data->xkb_context) {
   395         WAYLAND_xkb_context_unref(data->xkb_context);
   396         data->xkb_context = NULL;
   397     }
   398 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   399     if (data->windowmanager)
   400         qt_windowmanager_destroy(data->windowmanager);
   401 
   402     if (data->surface_extension)
   403         qt_surface_extension_destroy(data->surface_extension);
   404 
   405     Wayland_touch_destroy(data);
   406 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   407 
   408     if (data->shm)
   409         wl_shm_destroy(data->shm);
   410 
   411     if (data->cursor_theme)
   412         WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
   413 
   414     if (data->shell)
   415         wl_shell_destroy(data->shell);
   416 
   417     if (data->compositor)
   418         wl_compositor_destroy(data->compositor);
   419 
   420     if (data->display) {
   421         WAYLAND_wl_display_flush(data->display);
   422         WAYLAND_wl_display_disconnect(data->display);
   423     }
   424     
   425     wl_list_for_each_safe(m, t, &data->modes_list, link) {
   426         WAYLAND_wl_list_remove(&m->link);
   427         free(m);
   428     }
   429 
   430 
   431     free(data);
   432     _this->driverdata = NULL;
   433 }
   434 
   435 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   436 
   437 /* vi: set ts=4 sw=4 expandtab: */