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