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