src/video/wayland/SDL_waylandvideo.c
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10744 f42f107a6035
child 11030 06a801c7a54f
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 #include "SDL_waylandclipboard.h"
    38 
    39 #include <sys/types.h>
    40 #include <unistd.h>
    41 #include <fcntl.h>
    42 #include <xkbcommon/xkbcommon.h>
    43 
    44 #include "SDL_waylanddyn.h"
    45 #include <wayland-util.h>
    46 
    47 #define WAYLANDVID_DRIVER_NAME "wayland"
    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 /* Find out what class name we should use
    62  * Based on src/video/x11/SDL_x11video.c */
    63 static char *
    64 get_classname()
    65 {
    66     char *spot;
    67 #if defined(__LINUX__) || defined(__FREEBSD__)
    68     char procfile[1024];
    69     char linkfile[1024];
    70     int linksize;
    71 #endif
    72 
    73     /* First allow environment variable override */
    74     spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS");
    75     if (spot) {
    76         return SDL_strdup(spot);
    77     } else {
    78         /* Fallback to the "old" envvar */
    79         spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
    80         if (spot) {
    81             return SDL_strdup(spot);
    82         }
    83     }
    84 
    85     /* Next look at the application's executable name */
    86 #if defined(__LINUX__) || defined(__FREEBSD__)
    87 #if defined(__LINUX__)
    88     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
    89 #elif defined(__FREEBSD__)
    90     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
    91                  getpid());
    92 #else
    93 #error Where can we find the executable name?
    94 #endif
    95     linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
    96     if (linksize > 0) {
    97         linkfile[linksize] = '\0';
    98         spot = SDL_strrchr(linkfile, '/');
    99         if (spot) {
   100             return SDL_strdup(spot + 1);
   101         } else {
   102             return SDL_strdup(linkfile);
   103         }
   104     }
   105 #endif /* __LINUX__ || __FREEBSD__ */
   106 
   107     /* Finally use the default we've used forever */
   108     return SDL_strdup("SDL_App");
   109 }
   110 
   111 /* Wayland driver bootstrap functions */
   112 static int
   113 Wayland_Available(void)
   114 {
   115     struct wl_display *display = NULL;
   116     if (SDL_WAYLAND_LoadSymbols()) {
   117         display = WAYLAND_wl_display_connect(NULL);
   118         if (display != NULL) {
   119             WAYLAND_wl_display_disconnect(display);
   120         }
   121         SDL_WAYLAND_UnloadSymbols();
   122     }
   123 
   124     return (display != NULL);
   125 }
   126 
   127 static void
   128 Wayland_DeleteDevice(SDL_VideoDevice *device)
   129 {
   130     SDL_free(device);
   131     SDL_WAYLAND_UnloadSymbols();
   132 }
   133 
   134 static SDL_VideoDevice *
   135 Wayland_CreateDevice(int devindex)
   136 {
   137     SDL_VideoDevice *device;
   138 
   139     if (!SDL_WAYLAND_LoadSymbols()) {
   140         return NULL;
   141     }
   142 
   143     /* Initialize all variables that we clean on shutdown */
   144     device = SDL_calloc(1, sizeof(SDL_VideoDevice));
   145     if (!device) {
   146         SDL_WAYLAND_UnloadSymbols();
   147         SDL_OutOfMemory();
   148         return NULL;
   149     }
   150 
   151     /* Set the function pointers */
   152     device->VideoInit = Wayland_VideoInit;
   153     device->VideoQuit = Wayland_VideoQuit;
   154     device->SetDisplayMode = Wayland_SetDisplayMode;
   155     device->GetDisplayModes = Wayland_GetDisplayModes;
   156     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
   157 
   158     device->PumpEvents = Wayland_PumpEvents;
   159 
   160     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
   161     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
   162     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
   163     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
   164     device->GL_CreateContext = Wayland_GLES_CreateContext;
   165     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
   166     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
   167     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
   168     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
   169 
   170     device->CreateWindow = Wayland_CreateWindow;
   171     device->ShowWindow = Wayland_ShowWindow;
   172     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
   173     device->MaximizeWindow = Wayland_MaximizeWindow;
   174     device->RestoreWindow = Wayland_RestoreWindow;
   175     device->SetWindowSize = Wayland_SetWindowSize;
   176     device->SetWindowTitle = Wayland_SetWindowTitle;
   177     device->DestroyWindow = Wayland_DestroyWindow;
   178     device->SetWindowHitTest = Wayland_SetWindowHitTest;
   179 
   180     device->SetClipboardText = Wayland_SetClipboardText;
   181     device->GetClipboardText = Wayland_GetClipboardText;
   182     device->HasClipboardText = Wayland_HasClipboardText;
   183 
   184     device->free = Wayland_DeleteDevice;
   185 
   186     return device;
   187 }
   188 
   189 VideoBootStrap Wayland_bootstrap = {
   190     WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
   191     Wayland_Available, Wayland_CreateDevice
   192 };
   193 
   194 static void
   195 display_handle_geometry(void *data,
   196                         struct wl_output *output,
   197                         int x, int y,
   198                         int physical_width,
   199                         int physical_height,
   200                         int subpixel,
   201                         const char *make,
   202                         const char *model,
   203                         int transform)
   204 
   205 {
   206     SDL_VideoDisplay *display = data;
   207 
   208     display->name = SDL_strdup(model);
   209     display->driverdata = output;
   210 }
   211 
   212 static void
   213 display_handle_mode(void *data,
   214                     struct wl_output *output,
   215                     uint32_t flags,
   216                     int width,
   217                     int height,
   218                     int refresh)
   219 {
   220     SDL_VideoDisplay *display = data;
   221     SDL_DisplayMode mode;
   222 
   223     SDL_zero(mode);
   224     mode.format = SDL_PIXELFORMAT_RGB888;
   225     mode.w = width;
   226     mode.h = height;
   227     mode.refresh_rate = refresh / 1000; // mHz to Hz
   228     SDL_AddDisplayMode(display, &mode);
   229 
   230     if (flags & WL_OUTPUT_MODE_CURRENT) {
   231         display->current_mode = mode;
   232         display->desktop_mode = mode;
   233     }
   234 }
   235 
   236 static void
   237 display_handle_done(void *data,
   238                     struct wl_output *output)
   239 {
   240     SDL_VideoDisplay *display = data;
   241     SDL_AddVideoDisplay(display);
   242     SDL_free(display->name);
   243     SDL_free(display);
   244 }
   245 
   246 static void
   247 display_handle_scale(void *data,
   248                      struct wl_output *output,
   249                      int32_t factor)
   250 {
   251     // TODO: do HiDPI stuff.
   252 }
   253 
   254 static const struct wl_output_listener output_listener = {
   255     display_handle_geometry,
   256     display_handle_mode,
   257     display_handle_done,
   258     display_handle_scale
   259 };
   260 
   261 static void
   262 Wayland_add_display(SDL_VideoData *d, uint32_t id)
   263 {
   264     struct wl_output *output;
   265     SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
   266     if (!display) {
   267         SDL_OutOfMemory();
   268         return;
   269     }
   270     SDL_zero(*display);
   271 
   272     output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
   273     if (!output) {
   274         SDL_SetError("Failed to retrieve output.");
   275         SDL_free(display);
   276         return;
   277     }
   278 
   279     wl_output_add_listener(output, &output_listener, display);
   280 }
   281 
   282 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   283 static void
   284 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
   285         int32_t show_is_fullscreen)
   286 {
   287 }
   288 
   289 static void
   290 windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
   291 {
   292     SDL_SendQuit();
   293 }
   294 
   295 static const struct qt_windowmanager_listener windowmanager_listener = {
   296     windowmanager_hints,
   297     windowmanager_quit,
   298 };
   299 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   300 
   301 static void
   302 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   303                       const char *interface, uint32_t version)
   304 {
   305     SDL_VideoData *d = data;
   306 
   307     if (strcmp(interface, "wl_compositor") == 0) {
   308         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   309     } else if (strcmp(interface, "wl_output") == 0) {
   310         Wayland_add_display(d, id);
   311     } else if (strcmp(interface, "wl_seat") == 0) {
   312         Wayland_display_add_input(d, id);
   313     } else if (strcmp(interface, "wl_shell") == 0) {
   314         d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
   315     } else if (strcmp(interface, "wl_shm") == 0) {
   316         d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
   317         d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
   318     } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
   319         Wayland_display_add_relative_pointer_manager(d, id);
   320     } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
   321         Wayland_display_add_pointer_constraints(d, id);
   322     } else if (strcmp(interface, "wl_data_device_manager") == 0) {
   323         d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, 3);
   324 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   325     } else if (strcmp(interface, "qt_touch_extension") == 0) {
   326         Wayland_touch_create(d, id);
   327     } else if (strcmp(interface, "qt_surface_extension") == 0) {
   328         d->surface_extension = wl_registry_bind(registry, id,
   329                 &qt_surface_extension_interface, 1);
   330     } else if (strcmp(interface, "qt_windowmanager") == 0) {
   331         d->windowmanager = wl_registry_bind(registry, id,
   332                 &qt_windowmanager_interface, 1);
   333         qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
   334 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   335     }
   336 }
   337 
   338 static const struct wl_registry_listener registry_listener = {
   339     display_handle_global
   340 };
   341 
   342 int
   343 Wayland_VideoInit(_THIS)
   344 {
   345     SDL_VideoData *data = SDL_malloc(sizeof *data);
   346     if (data == NULL)
   347         return SDL_OutOfMemory();
   348     memset(data, 0, sizeof *data);
   349 
   350     _this->driverdata = data;
   351 
   352     data->xkb_context = WAYLAND_xkb_context_new(0);
   353     if (!data->xkb_context) {
   354         return SDL_SetError("Failed to create XKB context");
   355     }
   356 
   357     data->display = WAYLAND_wl_display_connect(NULL);
   358     if (data->display == NULL) {
   359         return SDL_SetError("Failed to connect to a Wayland display");
   360     }
   361 
   362     data->registry = wl_display_get_registry(data->display);
   363     if (data->registry == NULL) {
   364         return SDL_SetError("Failed to get the Wayland registry");
   365     }
   366 
   367     wl_registry_add_listener(data->registry, &registry_listener, data);
   368 
   369     // First roundtrip to receive all registry objects.
   370     WAYLAND_wl_display_roundtrip(data->display);
   371 
   372     // Second roundtrip to receive all output events.
   373     WAYLAND_wl_display_roundtrip(data->display);
   374 
   375     Wayland_InitMouse();
   376 
   377     /* Get the surface class name, usually the name of the application */
   378     data->classname = get_classname();
   379 
   380     WAYLAND_wl_display_flush(data->display);
   381 
   382     return 0;
   383 }
   384 
   385 static void
   386 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   387 {
   388     // Nothing to do here, everything was already done in the wl_output
   389     // callbacks.
   390 }
   391 
   392 static int
   393 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   394 {
   395     return SDL_Unsupported();
   396 }
   397 
   398 void
   399 Wayland_VideoQuit(_THIS)
   400 {
   401     SDL_VideoData *data = _this->driverdata;
   402     int i;
   403 
   404     Wayland_FiniMouse ();
   405 
   406     for (i = 0; i < _this->num_displays; ++i) {
   407         SDL_VideoDisplay *display = &_this->displays[i];
   408         wl_output_destroy(display->driverdata);
   409         display->driverdata = NULL;
   410     }
   411 
   412     Wayland_display_destroy_input(data);
   413     Wayland_display_destroy_pointer_constraints(data);
   414     Wayland_display_destroy_relative_pointer_manager(data);
   415 
   416     if (data->xkb_context) {
   417         WAYLAND_xkb_context_unref(data->xkb_context);
   418         data->xkb_context = NULL;
   419     }
   420 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   421     if (data->windowmanager)
   422         qt_windowmanager_destroy(data->windowmanager);
   423 
   424     if (data->surface_extension)
   425         qt_surface_extension_destroy(data->surface_extension);
   426 
   427     Wayland_touch_destroy(data);
   428 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   429 
   430     if (data->shm)
   431         wl_shm_destroy(data->shm);
   432 
   433     if (data->cursor_theme)
   434         WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
   435 
   436     if (data->shell)
   437         wl_shell_destroy(data->shell);
   438 
   439     if (data->compositor)
   440         wl_compositor_destroy(data->compositor);
   441 
   442     if (data->registry)
   443         wl_registry_destroy(data->registry);
   444 
   445     if (data->display) {
   446         WAYLAND_wl_display_flush(data->display);
   447         WAYLAND_wl_display_disconnect(data->display);
   448     }
   449 
   450     SDL_free(data->classname);
   451     free(data);
   452     _this->driverdata = NULL;
   453 }
   454 
   455 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   456 
   457 /* vi: set ts=4 sw=4 expandtab: */