src/video/wayland/SDL_waylandvideo.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 21 May 2019 17:33:31 -0700
changeset 12747 cdf53e16feb7
parent 12623 5b8e7e5bda1c
permissions -rw-r--r--
Fixed bug 4639 - CMake build does not generate libhidapi.so for Android

Manuel Sabogal

I noticed that the current Android.mk builds a libhidapi.so library for Android but the CMake build hasn't been updated to do so. I'll attach a patch that fixes this issue.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 #include "SDL_waylandvulkan.h"
    39 
    40 #include <sys/types.h>
    41 #include <unistd.h>
    42 #include <fcntl.h>
    43 #include <xkbcommon/xkbcommon.h>
    44 
    45 #include "SDL_waylanddyn.h"
    46 #include <wayland-util.h>
    47 
    48 #include "xdg-shell-client-protocol.h"
    49 #include "xdg-shell-unstable-v6-client-protocol.h"
    50 #include "xdg-decoration-unstable-v1-client-protocol.h"
    51 #include "org-kde-kwin-server-decoration-manager-client-protocol.h"
    52 
    53 #define WAYLANDVID_DRIVER_NAME "wayland"
    54 
    55 /* Initialization/Query functions */
    56 static int
    57 Wayland_VideoInit(_THIS);
    58 
    59 static void
    60 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
    61 static int
    62 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
    63 
    64 static void
    65 Wayland_VideoQuit(_THIS);
    66 
    67 /* Find out what class name we should use
    68  * Based on src/video/x11/SDL_x11video.c */
    69 static char *
    70 get_classname()
    71 {
    72 /* !!! FIXME: this is probably wrong, albeit harmless in many common cases. From protocol spec:
    73     "The surface class identifies the general class of applications
    74     to which the surface belongs. A common convention is to use the
    75     file name (or the full path if it is a non-standard location) of
    76     the application's .desktop file as the class." */
    77 
    78     char *spot;
    79 #if defined(__LINUX__) || defined(__FREEBSD__)
    80     char procfile[1024];
    81     char linkfile[1024];
    82     int linksize;
    83 #endif
    84 
    85     /* First allow environment variable override */
    86     spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS");
    87     if (spot) {
    88         return SDL_strdup(spot);
    89     } else {
    90         /* Fallback to the "old" envvar */
    91         spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
    92         if (spot) {
    93             return SDL_strdup(spot);
    94         }
    95     }
    96 
    97     /* Next look at the application's executable name */
    98 #if defined(__LINUX__) || defined(__FREEBSD__)
    99 #if defined(__LINUX__)
   100     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
   101 #elif defined(__FREEBSD__)
   102     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
   103                  getpid());
   104 #else
   105 #error Where can we find the executable name?
   106 #endif
   107     linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
   108     if (linksize > 0) {
   109         linkfile[linksize] = '\0';
   110         spot = SDL_strrchr(linkfile, '/');
   111         if (spot) {
   112             return SDL_strdup(spot + 1);
   113         } else {
   114             return SDL_strdup(linkfile);
   115         }
   116     }
   117 #endif /* __LINUX__ || __FREEBSD__ */
   118 
   119     /* Finally use the default we've used forever */
   120     return SDL_strdup("SDL_App");
   121 }
   122 
   123 /* Wayland driver bootstrap functions */
   124 static int
   125 Wayland_Available(void)
   126 {
   127     struct wl_display *display = NULL;
   128     if (SDL_WAYLAND_LoadSymbols()) {
   129         display = WAYLAND_wl_display_connect(NULL);
   130         if (display != NULL) {
   131             WAYLAND_wl_display_disconnect(display);
   132         }
   133         SDL_WAYLAND_UnloadSymbols();
   134     }
   135 
   136     return (display != NULL);
   137 }
   138 
   139 static void
   140 Wayland_DeleteDevice(SDL_VideoDevice *device)
   141 {
   142     SDL_free(device);
   143     SDL_WAYLAND_UnloadSymbols();
   144 }
   145 
   146 static SDL_VideoDevice *
   147 Wayland_CreateDevice(int devindex)
   148 {
   149     SDL_VideoDevice *device;
   150 
   151     if (!SDL_WAYLAND_LoadSymbols()) {
   152         return NULL;
   153     }
   154 
   155     /* Initialize all variables that we clean on shutdown */
   156     device = SDL_calloc(1, sizeof(SDL_VideoDevice));
   157     if (!device) {
   158         SDL_WAYLAND_UnloadSymbols();
   159         SDL_OutOfMemory();
   160         return NULL;
   161     }
   162 
   163     /* Set the function pointers */
   164     device->VideoInit = Wayland_VideoInit;
   165     device->VideoQuit = Wayland_VideoQuit;
   166     device->SetDisplayMode = Wayland_SetDisplayMode;
   167     device->GetDisplayModes = Wayland_GetDisplayModes;
   168     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
   169 
   170     device->PumpEvents = Wayland_PumpEvents;
   171 
   172     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
   173     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
   174     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
   175     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
   176     device->GL_CreateContext = Wayland_GLES_CreateContext;
   177     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
   178     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
   179     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
   180     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
   181 
   182     device->CreateSDLWindow = Wayland_CreateWindow;
   183     device->ShowWindow = Wayland_ShowWindow;
   184     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
   185     device->MaximizeWindow = Wayland_MaximizeWindow;
   186     device->RestoreWindow = Wayland_RestoreWindow;
   187     device->SetWindowBordered = Wayland_SetWindowBordered;
   188     device->SetWindowSize = Wayland_SetWindowSize;
   189     device->SetWindowTitle = Wayland_SetWindowTitle;
   190     device->DestroyWindow = Wayland_DestroyWindow;
   191     device->SetWindowHitTest = Wayland_SetWindowHitTest;
   192 
   193     device->SetClipboardText = Wayland_SetClipboardText;
   194     device->GetClipboardText = Wayland_GetClipboardText;
   195     device->HasClipboardText = Wayland_HasClipboardText;
   196 
   197 #if SDL_VIDEO_VULKAN
   198     device->Vulkan_LoadLibrary = Wayland_Vulkan_LoadLibrary;
   199     device->Vulkan_UnloadLibrary = Wayland_Vulkan_UnloadLibrary;
   200     device->Vulkan_GetInstanceExtensions = Wayland_Vulkan_GetInstanceExtensions;
   201     device->Vulkan_CreateSurface = Wayland_Vulkan_CreateSurface;
   202 #endif
   203 
   204     device->free = Wayland_DeleteDevice;
   205 
   206     return device;
   207 }
   208 
   209 VideoBootStrap Wayland_bootstrap = {
   210     WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
   211     Wayland_Available, Wayland_CreateDevice
   212 };
   213 
   214 static void
   215 display_handle_geometry(void *data,
   216                         struct wl_output *output,
   217                         int x, int y,
   218                         int physical_width,
   219                         int physical_height,
   220                         int subpixel,
   221                         const char *make,
   222                         const char *model,
   223                         int transform)
   224 
   225 {
   226     SDL_VideoDisplay *display = data;
   227 
   228     display->name = SDL_strdup(model);
   229     display->driverdata = output;
   230 }
   231 
   232 static void
   233 display_handle_mode(void *data,
   234                     struct wl_output *output,
   235                     uint32_t flags,
   236                     int width,
   237                     int height,
   238                     int refresh)
   239 {
   240     SDL_VideoDisplay *display = data;
   241     SDL_DisplayMode mode;
   242 
   243     SDL_zero(mode);
   244     mode.format = SDL_PIXELFORMAT_RGB888;
   245     mode.w = width;
   246     mode.h = height;
   247     mode.refresh_rate = refresh / 1000; // mHz to Hz
   248     mode.driverdata = display->driverdata;
   249     SDL_AddDisplayMode(display, &mode);
   250 
   251     if (flags & WL_OUTPUT_MODE_CURRENT) {
   252         display->current_mode = mode;
   253         display->desktop_mode = mode;
   254     }
   255 }
   256 
   257 static void
   258 display_handle_done(void *data,
   259                     struct wl_output *output)
   260 {
   261     SDL_VideoDisplay *display = data;
   262     SDL_AddVideoDisplay(display);
   263     SDL_free(display->name);
   264     SDL_free(display);
   265 }
   266 
   267 static void
   268 display_handle_scale(void *data,
   269                      struct wl_output *output,
   270                      int32_t factor)
   271 {
   272     // TODO: do HiDPI stuff.
   273 }
   274 
   275 static const struct wl_output_listener output_listener = {
   276     display_handle_geometry,
   277     display_handle_mode,
   278     display_handle_done,
   279     display_handle_scale
   280 };
   281 
   282 static void
   283 Wayland_add_display(SDL_VideoData *d, uint32_t id)
   284 {
   285     struct wl_output *output;
   286     SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
   287     if (!display) {
   288         SDL_OutOfMemory();
   289         return;
   290     }
   291     SDL_zero(*display);
   292 
   293     output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
   294     if (!output) {
   295         SDL_SetError("Failed to retrieve output.");
   296         SDL_free(display);
   297         return;
   298     }
   299 
   300     wl_output_add_listener(output, &output_listener, display);
   301 }
   302 
   303 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   304 static void
   305 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
   306         int32_t show_is_fullscreen)
   307 {
   308 }
   309 
   310 static void
   311 windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
   312 {
   313     SDL_SendQuit();
   314 }
   315 
   316 static const struct qt_windowmanager_listener windowmanager_listener = {
   317     windowmanager_hints,
   318     windowmanager_quit,
   319 };
   320 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   321 
   322 
   323 static void
   324 handle_ping_zxdg_shell(void *data, struct zxdg_shell_v6 *zxdg, uint32_t serial)
   325 {
   326     zxdg_shell_v6_pong(zxdg, serial);
   327 }
   328 
   329 static const struct zxdg_shell_v6_listener shell_listener_zxdg = {
   330     handle_ping_zxdg_shell
   331 };
   332 
   333 
   334 static void
   335 handle_ping_xdg_wm_base(void *data, struct xdg_wm_base *xdg, uint32_t serial)
   336 {
   337     xdg_wm_base_pong(xdg, serial);
   338 }
   339 
   340 static const struct xdg_wm_base_listener shell_listener_xdg = {
   341     handle_ping_xdg_wm_base
   342 };
   343 
   344 
   345 static void
   346 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   347                       const char *interface, uint32_t version)
   348 {
   349     SDL_VideoData *d = data;
   350 
   351     /*printf("WAYLAND INTERFACE: %s\n", interface);*/
   352 
   353     if (strcmp(interface, "wl_compositor") == 0) {
   354         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   355     } else if (strcmp(interface, "wl_output") == 0) {
   356         Wayland_add_display(d, id);
   357     } else if (strcmp(interface, "wl_seat") == 0) {
   358         Wayland_display_add_input(d, id);
   359     } else if (strcmp(interface, "xdg_wm_base") == 0) {
   360         d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1);
   361         xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL);
   362     } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
   363         d->shell.zxdg = wl_registry_bind(d->registry, id, &zxdg_shell_v6_interface, 1);
   364         zxdg_shell_v6_add_listener(d->shell.zxdg, &shell_listener_zxdg, NULL);
   365     } else if (strcmp(interface, "wl_shell") == 0) {
   366         d->shell.wl = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
   367     } else if (strcmp(interface, "wl_shm") == 0) {
   368         d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
   369         d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
   370     } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
   371         Wayland_display_add_relative_pointer_manager(d, id);
   372     } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
   373         Wayland_display_add_pointer_constraints(d, id);
   374     } else if (strcmp(interface, "wl_data_device_manager") == 0) {
   375         d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, 3);
   376     } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
   377         d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1);
   378     } else if (strcmp(interface, "org_kde_kwin_server_decoration_manager") == 0) {
   379         d->kwin_server_decoration_manager = wl_registry_bind(d->registry, id, &org_kde_kwin_server_decoration_manager_interface, 1);
   380 
   381 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   382     } else if (strcmp(interface, "qt_touch_extension") == 0) {
   383         Wayland_touch_create(d, id);
   384     } else if (strcmp(interface, "qt_surface_extension") == 0) {
   385         d->surface_extension = wl_registry_bind(registry, id,
   386                 &qt_surface_extension_interface, 1);
   387     } else if (strcmp(interface, "qt_windowmanager") == 0) {
   388         d->windowmanager = wl_registry_bind(registry, id,
   389                 &qt_windowmanager_interface, 1);
   390         qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
   391 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   392     }
   393 }
   394 
   395 static void
   396 display_remove_global(void *data, struct wl_registry *registry, uint32_t id) {}
   397 
   398 static const struct wl_registry_listener registry_listener = {
   399     display_handle_global,
   400     display_remove_global
   401 };
   402 
   403 int
   404 Wayland_VideoInit(_THIS)
   405 {
   406     SDL_VideoData *data = SDL_malloc(sizeof *data);
   407     if (data == NULL)
   408         return SDL_OutOfMemory();
   409     memset(data, 0, sizeof *data);
   410 
   411     _this->driverdata = data;
   412 
   413     data->xkb_context = WAYLAND_xkb_context_new(0);
   414     if (!data->xkb_context) {
   415         return SDL_SetError("Failed to create XKB context");
   416     }
   417 
   418     data->display = WAYLAND_wl_display_connect(NULL);
   419     if (data->display == NULL) {
   420         return SDL_SetError("Failed to connect to a Wayland display");
   421     }
   422 
   423     data->registry = wl_display_get_registry(data->display);
   424     if (data->registry == NULL) {
   425         return SDL_SetError("Failed to get the Wayland registry");
   426     }
   427 
   428     wl_registry_add_listener(data->registry, &registry_listener, data);
   429 
   430     // First roundtrip to receive all registry objects.
   431     WAYLAND_wl_display_roundtrip(data->display);
   432 
   433     // Second roundtrip to receive all output events.
   434     WAYLAND_wl_display_roundtrip(data->display);
   435 
   436     Wayland_InitMouse();
   437 
   438     /* Get the surface class name, usually the name of the application */
   439     data->classname = get_classname();
   440 
   441     WAYLAND_wl_display_flush(data->display);
   442 
   443     return 0;
   444 }
   445 
   446 static void
   447 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   448 {
   449     // Nothing to do here, everything was already done in the wl_output
   450     // callbacks.
   451 }
   452 
   453 static int
   454 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   455 {
   456     return SDL_Unsupported();
   457 }
   458 
   459 void
   460 Wayland_VideoQuit(_THIS)
   461 {
   462     SDL_VideoData *data = _this->driverdata;
   463     int i, j;
   464 
   465     Wayland_FiniMouse ();
   466 
   467     for (i = 0; i < _this->num_displays; ++i) {
   468         SDL_VideoDisplay *display = &_this->displays[i];
   469         wl_output_destroy(display->driverdata);
   470         display->driverdata = NULL;
   471 
   472         for (j = display->num_display_modes; j--;) {
   473             display->display_modes[j].driverdata = NULL;
   474         }
   475         display->desktop_mode.driverdata = NULL;
   476     }
   477 
   478     Wayland_display_destroy_input(data);
   479     Wayland_display_destroy_pointer_constraints(data);
   480     Wayland_display_destroy_relative_pointer_manager(data);
   481 
   482     if (data->xkb_context) {
   483         WAYLAND_xkb_context_unref(data->xkb_context);
   484         data->xkb_context = NULL;
   485     }
   486 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   487     if (data->windowmanager)
   488         qt_windowmanager_destroy(data->windowmanager);
   489 
   490     if (data->surface_extension)
   491         qt_surface_extension_destroy(data->surface_extension);
   492 
   493     Wayland_touch_destroy(data);
   494 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
   495 
   496     if (data->shm)
   497         wl_shm_destroy(data->shm);
   498 
   499     if (data->cursor_theme)
   500         WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
   501 
   502     if (data->shell.wl)
   503         wl_shell_destroy(data->shell.wl);
   504 
   505     if (data->shell.xdg)
   506         xdg_wm_base_destroy(data->shell.xdg);
   507 
   508     if (data->shell.zxdg)
   509         zxdg_shell_v6_destroy(data->shell.zxdg);
   510 
   511     if (data->compositor)
   512         wl_compositor_destroy(data->compositor);
   513 
   514     if (data->registry)
   515         wl_registry_destroy(data->registry);
   516 
   517     if (data->display) {
   518         WAYLAND_wl_display_flush(data->display);
   519         WAYLAND_wl_display_disconnect(data->display);
   520     }
   521 
   522     SDL_free(data->classname);
   523     SDL_free(data);
   524     _this->driverdata = NULL;
   525 }
   526 
   527 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   528 
   529 /* vi: set ts=4 sw=4 expandtab: */