src/video/wayland/SDL_waylandvideo.c
author Ryan C. Gordon
Tue, 07 Apr 2015 22:49:56 -0400
changeset 9469 3f8d36ffd19d
parent 9467 975453c4e217
child 9472 14813191e6cf
permissions -rw-r--r--
Wayland: changed a few "SetError(); return -1;" to "return SetError()".
     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 /* Initialization/Query functions */
    47 static int
    48 Wayland_VideoInit(_THIS);
    49 
    50 static void
    51 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
    52 static int
    53 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
    54 
    55 static void
    56 Wayland_VideoQuit(_THIS);
    57 
    58 /* Wayland driver bootstrap functions */
    59 static int
    60 Wayland_Available(void)
    61 {
    62     struct wl_display *display = NULL;
    63     if (SDL_WAYLAND_LoadSymbols()) {
    64         display = WAYLAND_wl_display_connect(NULL);
    65         if (display != NULL) {
    66             WAYLAND_wl_display_disconnect(display);
    67         }
    68         SDL_WAYLAND_UnloadSymbols();
    69     }
    70 
    71     return (display != NULL);
    72 }
    73 
    74 static void
    75 Wayland_DeleteDevice(SDL_VideoDevice *device)
    76 {
    77     SDL_free(device);
    78     SDL_WAYLAND_UnloadSymbols();
    79 }
    80 
    81 static SDL_VideoDevice *
    82 Wayland_CreateDevice(int devindex)
    83 {
    84     SDL_VideoDevice *device;
    85 
    86     if (!SDL_WAYLAND_LoadSymbols()) {
    87         return NULL;
    88     }
    89 
    90     /* Initialize all variables that we clean on shutdown */
    91     device = SDL_calloc(1, sizeof(SDL_VideoDevice));
    92     if (!device) {
    93         SDL_WAYLAND_UnloadSymbols();
    94         SDL_OutOfMemory();
    95         return NULL;
    96     }
    97 
    98     /* Set the function pointers */
    99     device->VideoInit = Wayland_VideoInit;
   100     device->VideoQuit = Wayland_VideoQuit;
   101     device->SetDisplayMode = Wayland_SetDisplayMode;
   102     device->GetDisplayModes = Wayland_GetDisplayModes;
   103     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
   104 
   105     device->PumpEvents = Wayland_PumpEvents;
   106 
   107     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
   108     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
   109     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
   110     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
   111     device->GL_CreateContext = Wayland_GLES_CreateContext;
   112     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
   113     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
   114     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
   115     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
   116 
   117     device->CreateWindow = Wayland_CreateWindow;
   118     device->ShowWindow = Wayland_ShowWindow;
   119     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
   120     device->SetWindowSize = Wayland_SetWindowSize;
   121     device->DestroyWindow = Wayland_DestroyWindow;
   122 
   123     device->free = Wayland_DeleteDevice;
   124 
   125     return device;
   126 }
   127 
   128 VideoBootStrap Wayland_bootstrap = {
   129     WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
   130     Wayland_Available, Wayland_CreateDevice
   131 };
   132 
   133 static void
   134 display_handle_geometry(void *data,
   135                         struct wl_output *output,
   136                         int x, int y,
   137                         int physical_width,
   138                         int physical_height,
   139                         int subpixel,
   140                         const char *make,
   141                         const char *model,
   142                         int transform)
   143 
   144 {
   145     SDL_VideoDisplay *display = data;
   146 
   147     display->name = strdup(model);
   148     display->driverdata = output;
   149 }
   150 
   151 static void
   152 display_handle_mode(void *data,
   153                     struct wl_output *output,
   154                     uint32_t flags,
   155                     int width,
   156                     int height,
   157                     int refresh)
   158 {
   159     SDL_VideoDisplay *display = data;
   160     SDL_DisplayMode mode;
   161 
   162     SDL_zero(mode);
   163     mode.w = width;
   164     mode.h = height;
   165     mode.refresh_rate = refresh / 1000; // mHz to Hz
   166     SDL_AddDisplayMode(display, &mode);
   167 
   168     if (flags & WL_OUTPUT_MODE_CURRENT) {
   169         display->current_mode = mode;
   170         display->desktop_mode = mode;
   171     }
   172 }
   173 
   174 static void
   175 display_handle_done(void *data,
   176                     struct wl_output *output)
   177 {
   178     SDL_VideoDisplay *display = data;
   179     SDL_AddVideoDisplay(display);
   180     SDL_free(display->name);
   181     SDL_free(display);
   182 }
   183 
   184 static void
   185 display_handle_scale(void *data,
   186                      struct wl_output *output,
   187                      int32_t factor)
   188 {
   189     // TODO: do HiDPI stuff.
   190 }
   191 
   192 static const struct wl_output_listener output_listener = {
   193     display_handle_geometry,
   194     display_handle_mode,
   195     display_handle_done,
   196     display_handle_scale
   197 };
   198 
   199 static void
   200 Wayland_add_display(SDL_VideoData *d, uint32_t id)
   201 {
   202     SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
   203     if (!display) {
   204         SDL_OutOfMemory();
   205         return;
   206     }
   207     SDL_zero(*display);
   208 
   209     struct wl_output *output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
   210     if (!output) {
   211         SDL_SetError("Failed to retrieve output.");
   212         return;
   213     }
   214 
   215     wl_output_add_listener(output, &output_listener, display);
   216 }
   217 
   218 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   219 static void
   220 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
   221         int32_t show_is_fullscreen)
   222 {
   223 }
   224 
   225 static void
   226 windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
   227 {
   228     SDL_SendQuit();
   229 }
   230 
   231 static const struct qt_windowmanager_listener windowmanager_listener = {
   232     windowmanager_hints,
   233     windowmanager_quit,
   234 };
   235 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   236 
   237 static void
   238 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   239                       const char *interface, uint32_t version)
   240 {
   241     SDL_VideoData *d = data;
   242 
   243     if (strcmp(interface, "wl_compositor") == 0) {
   244         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   245     } else if (strcmp(interface, "wl_output") == 0) {
   246         Wayland_add_display(d, id);
   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 
   256 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   257     } else if (strcmp(interface, "qt_touch_extension") == 0) {
   258         Wayland_touch_create(d, id);
   259     } else if (strcmp(interface, "qt_surface_extension") == 0) {
   260         d->surface_extension = wl_registry_bind(registry, id,
   261                 &qt_surface_extension_interface, 1);
   262     } else if (strcmp(interface, "qt_windowmanager") == 0) {
   263         d->windowmanager = wl_registry_bind(registry, id,
   264                 &qt_windowmanager_interface, 1);
   265         qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
   266 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   267     }
   268 }
   269 
   270 static const struct wl_registry_listener registry_listener = {
   271     display_handle_global
   272 };
   273 
   274 int
   275 Wayland_VideoInit(_THIS)
   276 {
   277     SDL_VideoData *data = SDL_malloc(sizeof *data);
   278     if (data == NULL)
   279         return 0;
   280     memset(data, 0, sizeof *data);
   281 
   282     _this->driverdata = data;
   283 
   284     data->display = WAYLAND_wl_display_connect(NULL);
   285     if (data->display == NULL) {
   286         SDL_SetError("Failed to connect to a Wayland display");
   287         return 0;
   288     }
   289 
   290     data->registry = wl_display_get_registry(data->display);
   291     if (data->registry == NULL) {
   292         SDL_SetError("Failed to get the Wayland registry");
   293         return 0;
   294     }
   295 
   296     wl_registry_add_listener(data->registry, &registry_listener, data);
   297 
   298     // First roundtrip to receive all registry objects.
   299     wl_display_roundtrip(data->display);
   300 
   301     // Second roundtrip to receive all output events.
   302     wl_display_roundtrip(data->display);
   303 
   304     data->xkb_context = WAYLAND_xkb_context_new(0);
   305     if (!data->xkb_context) {
   306         SDL_SetError("Failed to create XKB context");
   307         return 0;
   308     }
   309 
   310     Wayland_InitMouse();
   311 
   312     WAYLAND_wl_display_flush(data->display);
   313 
   314     return 0;
   315 }
   316 
   317 static void
   318 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   319 {
   320     // Nothing to do here, everything was already done in the wl_output
   321     // callbacks.
   322 }
   323 
   324 static int
   325 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   326 {
   327     return SDL_Unsupported();
   328 }
   329 
   330 void
   331 Wayland_VideoQuit(_THIS)
   332 {
   333     SDL_VideoData *data = _this->driverdata;
   334     int i;
   335 
   336     Wayland_FiniMouse ();
   337 
   338     for (i = 0; i < _this->num_displays; ++i) {
   339         SDL_VideoDisplay *display = &_this->displays[i];
   340         wl_output_destroy(display->driverdata);
   341         display->driverdata = NULL;
   342     }
   343 
   344     Wayland_display_destroy_input(data);
   345 
   346     if (data->xkb_context) {
   347         WAYLAND_xkb_context_unref(data->xkb_context);
   348         data->xkb_context = NULL;
   349     }
   350 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   351     if (data->windowmanager)
   352         qt_windowmanager_destroy(data->windowmanager);
   353 
   354     if (data->surface_extension)
   355         qt_surface_extension_destroy(data->surface_extension);
   356 
   357     Wayland_touch_destroy(data);
   358 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   359 
   360     if (data->shm)
   361         wl_shm_destroy(data->shm);
   362 
   363     if (data->cursor_theme)
   364         WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
   365 
   366     if (data->shell)
   367         wl_shell_destroy(data->shell);
   368 
   369     if (data->compositor)
   370         wl_compositor_destroy(data->compositor);
   371 
   372     if (data->registry)
   373         wl_registry_destroy(data->registry);
   374 
   375     if (data->display) {
   376         WAYLAND_wl_display_flush(data->display);
   377         WAYLAND_wl_display_disconnect(data->display);
   378     }
   379 
   380     free(data);
   381     _this->driverdata = NULL;
   382 }
   383 
   384 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   385 
   386 /* vi: set ts=4 sw=4 expandtab: */