summaryrefslogtreecommitdiff
path: root/source/3rd-party/SDL2/src/video/wayland/SDL_waylandvideo.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/3rd-party/SDL2/src/video/wayland/SDL_waylandvideo.c')
-rw-r--r--source/3rd-party/SDL2/src/video/wayland/SDL_waylandvideo.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/video/wayland/SDL_waylandvideo.c b/source/3rd-party/SDL2/src/video/wayland/SDL_waylandvideo.c
new file mode 100644
index 0000000..b6155e7
--- /dev/null
+++ b/source/3rd-party/SDL2/src/video/wayland/SDL_waylandvideo.c
@@ -0,0 +1,517 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WAYLAND
+
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "SDL_stdinc.h"
+#include "../../events/SDL_events_c.h"
+
+#include "SDL_waylandvideo.h"
+#include "SDL_waylandevents_c.h"
+#include "SDL_waylandwindow.h"
+#include "SDL_waylandopengles.h"
+#include "SDL_waylandmouse.h"
+#include "SDL_waylandtouch.h"
+#include "SDL_waylandclipboard.h"
+#include "SDL_waylandvulkan.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include "SDL_waylanddyn.h"
+#include <wayland-util.h>
+
+#include "xdg-shell-client-protocol.h"
+#include "xdg-shell-unstable-v6-client-protocol.h"
+
+#define WAYLANDVID_DRIVER_NAME "wayland"
+
+/* Initialization/Query functions */
+static int
+Wayland_VideoInit(_THIS);
+
+static void
+Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
+static int
+Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
+
+static void
+Wayland_VideoQuit(_THIS);
+
+/* Find out what class name we should use
+ * Based on src/video/x11/SDL_x11video.c */
+static char *
+get_classname()
+{
+/* !!! FIXME: this is probably wrong, albeit harmless in many common cases. From protocol spec:
+ "The surface class identifies the general class of applications
+ to which the surface belongs. A common convention is to use the
+ file name (or the full path if it is a non-standard location) of
+ the application's .desktop file as the class." */
+
+ char *spot;
+#if defined(__LINUX__) || defined(__FREEBSD__)
+ char procfile[1024];
+ char linkfile[1024];
+ int linksize;
+#endif
+
+ /* First allow environment variable override */
+ spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS");
+ if (spot) {
+ return SDL_strdup(spot);
+ } else {
+ /* Fallback to the "old" envvar */
+ spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
+ if (spot) {
+ return SDL_strdup(spot);
+ }
+ }
+
+ /* Next look at the application's executable name */
+#if defined(__LINUX__) || defined(__FREEBSD__)
+#if defined(__LINUX__)
+ SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
+#elif defined(__FREEBSD__)
+ SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
+ getpid());
+#else
+#error Where can we find the executable name?
+#endif
+ linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
+ if (linksize > 0) {
+ linkfile[linksize] = '\0';
+ spot = SDL_strrchr(linkfile, '/');
+ if (spot) {
+ return SDL_strdup(spot + 1);
+ } else {
+ return SDL_strdup(linkfile);
+ }
+ }
+#endif /* __LINUX__ || __FREEBSD__ */
+
+ /* Finally use the default we've used forever */
+ return SDL_strdup("SDL_App");
+}
+
+/* Wayland driver bootstrap functions */
+static int
+Wayland_Available(void)
+{
+ struct wl_display *display = NULL;
+ if (SDL_WAYLAND_LoadSymbols()) {
+ display = WAYLAND_wl_display_connect(NULL);
+ if (display != NULL) {
+ WAYLAND_wl_display_disconnect(display);
+ }
+ SDL_WAYLAND_UnloadSymbols();
+ }
+
+ return (display != NULL);
+}
+
+static void
+Wayland_DeleteDevice(SDL_VideoDevice *device)
+{
+ SDL_free(device);
+ SDL_WAYLAND_UnloadSymbols();
+}
+
+static SDL_VideoDevice *
+Wayland_CreateDevice(int devindex)
+{
+ SDL_VideoDevice *device;
+
+ if (!SDL_WAYLAND_LoadSymbols()) {
+ return NULL;
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+ device = SDL_calloc(1, sizeof(SDL_VideoDevice));
+ if (!device) {
+ SDL_WAYLAND_UnloadSymbols();
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ /* Set the function pointers */
+ device->VideoInit = Wayland_VideoInit;
+ device->VideoQuit = Wayland_VideoQuit;
+ device->SetDisplayMode = Wayland_SetDisplayMode;
+ device->GetDisplayModes = Wayland_GetDisplayModes;
+ device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
+
+ device->PumpEvents = Wayland_PumpEvents;
+
+ device->GL_SwapWindow = Wayland_GLES_SwapWindow;
+ device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
+ device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
+ device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
+ device->GL_CreateContext = Wayland_GLES_CreateContext;
+ device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
+ device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
+ device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
+ device->GL_DeleteContext = Wayland_GLES_DeleteContext;
+
+ device->CreateSDLWindow = Wayland_CreateWindow;
+ device->ShowWindow = Wayland_ShowWindow;
+ device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
+ device->MaximizeWindow = Wayland_MaximizeWindow;
+ device->RestoreWindow = Wayland_RestoreWindow;
+ device->SetWindowSize = Wayland_SetWindowSize;
+ device->SetWindowTitle = Wayland_SetWindowTitle;
+ device->DestroyWindow = Wayland_DestroyWindow;
+ device->SetWindowHitTest = Wayland_SetWindowHitTest;
+
+ device->SetClipboardText = Wayland_SetClipboardText;
+ device->GetClipboardText = Wayland_GetClipboardText;
+ device->HasClipboardText = Wayland_HasClipboardText;
+
+#if SDL_VIDEO_VULKAN
+ device->Vulkan_LoadLibrary = Wayland_Vulkan_LoadLibrary;
+ device->Vulkan_UnloadLibrary = Wayland_Vulkan_UnloadLibrary;
+ device->Vulkan_GetInstanceExtensions = Wayland_Vulkan_GetInstanceExtensions;
+ device->Vulkan_CreateSurface = Wayland_Vulkan_CreateSurface;
+#endif
+
+ device->free = Wayland_DeleteDevice;
+
+ return device;
+}
+
+VideoBootStrap Wayland_bootstrap = {
+ WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
+ Wayland_Available, Wayland_CreateDevice
+};
+
+static void
+display_handle_geometry(void *data,
+ struct wl_output *output,
+ int x, int y,
+ int physical_width,
+ int physical_height,
+ int subpixel,
+ const char *make,
+ const char *model,
+ int transform)
+
+{
+ SDL_VideoDisplay *display = data;
+
+ display->name = SDL_strdup(model);
+ display->driverdata = output;
+}
+
+static void
+display_handle_mode(void *data,
+ struct wl_output *output,
+ uint32_t flags,
+ int width,
+ int height,
+ int refresh)
+{
+ SDL_VideoDisplay *display = data;
+ SDL_DisplayMode mode;
+
+ SDL_zero(mode);
+ mode.format = SDL_PIXELFORMAT_RGB888;
+ mode.w = width;
+ mode.h = height;
+ mode.refresh_rate = refresh / 1000; // mHz to Hz
+ mode.driverdata = display->driverdata;
+ SDL_AddDisplayMode(display, &mode);
+
+ if (flags & WL_OUTPUT_MODE_CURRENT) {
+ display->current_mode = mode;
+ display->desktop_mode = mode;
+ }
+}
+
+static void
+display_handle_done(void *data,
+ struct wl_output *output)
+{
+ SDL_VideoDisplay *display = data;
+ SDL_AddVideoDisplay(display);
+ SDL_free(display->name);
+ SDL_free(display);
+}
+
+static void
+display_handle_scale(void *data,
+ struct wl_output *output,
+ int32_t factor)
+{
+ // TODO: do HiDPI stuff.
+}
+
+static const struct wl_output_listener output_listener = {
+ display_handle_geometry,
+ display_handle_mode,
+ display_handle_done,
+ display_handle_scale
+};
+
+static void
+Wayland_add_display(SDL_VideoData *d, uint32_t id)
+{
+ struct wl_output *output;
+ SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
+ if (!display) {
+ SDL_OutOfMemory();
+ return;
+ }
+ SDL_zero(*display);
+
+ output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
+ if (!output) {
+ SDL_SetError("Failed to retrieve output.");
+ SDL_free(display);
+ return;
+ }
+
+ wl_output_add_listener(output, &output_listener, display);
+}
+
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
+static void
+windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
+ int32_t show_is_fullscreen)
+{
+}
+
+static void
+windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
+{
+ SDL_SendQuit();
+}
+
+static const struct qt_windowmanager_listener windowmanager_listener = {
+ windowmanager_hints,
+ windowmanager_quit,
+};
+#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
+
+
+static void
+handle_ping_zxdg_shell(void *data, struct zxdg_shell_v6 *zxdg, uint32_t serial)
+{
+ zxdg_shell_v6_pong(zxdg, serial);
+}
+
+static const struct zxdg_shell_v6_listener shell_listener_zxdg = {
+ handle_ping_zxdg_shell
+};
+
+
+static void
+handle_ping_xdg_wm_base(void *data, struct xdg_wm_base *xdg, uint32_t serial)
+{
+ xdg_wm_base_pong(xdg, serial);
+}
+
+static const struct xdg_wm_base_listener shell_listener_xdg = {
+ handle_ping_xdg_wm_base
+};
+
+
+static void
+display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
+ const char *interface, uint32_t version)
+{
+ SDL_VideoData *d = data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_output") == 0) {
+ Wayland_add_display(d, id);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ Wayland_display_add_input(d, id);
+ } else if (strcmp(interface, "xdg_wm_base") == 0) {
+ d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1);
+ xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL);
+ } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
+ d->shell.zxdg = wl_registry_bind(d->registry, id, &zxdg_shell_v6_interface, 1);
+ zxdg_shell_v6_add_listener(d->shell.zxdg, &shell_listener_zxdg, NULL);
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ d->shell.wl = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+ d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
+ } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
+ Wayland_display_add_relative_pointer_manager(d, id);
+ } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
+ Wayland_display_add_pointer_constraints(d, id);
+ } else if (strcmp(interface, "wl_data_device_manager") == 0) {
+ d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, 3);
+
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
+ } else if (strcmp(interface, "qt_touch_extension") == 0) {
+ Wayland_touch_create(d, id);
+ } else if (strcmp(interface, "qt_surface_extension") == 0) {
+ d->surface_extension = wl_registry_bind(registry, id,
+ &qt_surface_extension_interface, 1);
+ } else if (strcmp(interface, "qt_windowmanager") == 0) {
+ d->windowmanager = wl_registry_bind(registry, id,
+ &qt_windowmanager_interface, 1);
+ qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
+#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
+ }
+}
+
+static const struct wl_registry_listener registry_listener = {
+ display_handle_global,
+ NULL, /* global_remove */
+};
+
+int
+Wayland_VideoInit(_THIS)
+{
+ SDL_VideoData *data = SDL_malloc(sizeof *data);
+ if (data == NULL)
+ return SDL_OutOfMemory();
+ memset(data, 0, sizeof *data);
+
+ _this->driverdata = data;
+
+ data->xkb_context = WAYLAND_xkb_context_new(0);
+ if (!data->xkb_context) {
+ return SDL_SetError("Failed to create XKB context");
+ }
+
+ data->display = WAYLAND_wl_display_connect(NULL);
+ if (data->display == NULL) {
+ return SDL_SetError("Failed to connect to a Wayland display");
+ }
+
+ data->registry = wl_display_get_registry(data->display);
+ if (data->registry == NULL) {
+ return SDL_SetError("Failed to get the Wayland registry");
+ }
+
+ wl_registry_add_listener(data->registry, &registry_listener, data);
+
+ // First roundtrip to receive all registry objects.
+ WAYLAND_wl_display_roundtrip(data->display);
+
+ // Second roundtrip to receive all output events.
+ WAYLAND_wl_display_roundtrip(data->display);
+
+ Wayland_InitMouse();
+
+ /* Get the surface class name, usually the name of the application */
+ data->classname = get_classname();
+
+ WAYLAND_wl_display_flush(data->display);
+
+ return 0;
+}
+
+static void
+Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
+{
+ // Nothing to do here, everything was already done in the wl_output
+ // callbacks.
+}
+
+static int
+Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
+{
+ return SDL_Unsupported();
+}
+
+void
+Wayland_VideoQuit(_THIS)
+{
+ SDL_VideoData *data = _this->driverdata;
+ int i, j;
+
+ Wayland_FiniMouse ();
+
+ for (i = 0; i < _this->num_displays; ++i) {
+ SDL_VideoDisplay *display = &_this->displays[i];
+ wl_output_destroy(display->driverdata);
+ display->driverdata = NULL;
+
+ for (j = display->num_display_modes; j--;) {
+ display->display_modes[j].driverdata = NULL;
+ }
+ display->desktop_mode.driverdata = NULL;
+ }
+
+ Wayland_display_destroy_input(data);
+ Wayland_display_destroy_pointer_constraints(data);
+ Wayland_display_destroy_relative_pointer_manager(data);
+
+ if (data->xkb_context) {
+ WAYLAND_xkb_context_unref(data->xkb_context);
+ data->xkb_context = NULL;
+ }
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
+ if (data->windowmanager)
+ qt_windowmanager_destroy(data->windowmanager);
+
+ if (data->surface_extension)
+ qt_surface_extension_destroy(data->surface_extension);
+
+ Wayland_touch_destroy(data);
+#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
+
+ if (data->shm)
+ wl_shm_destroy(data->shm);
+
+ if (data->cursor_theme)
+ WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
+
+ if (data->shell.wl)
+ wl_shell_destroy(data->shell.wl);
+
+ if (data->shell.xdg)
+ xdg_wm_base_destroy(data->shell.xdg);
+
+ if (data->shell.zxdg)
+ zxdg_shell_v6_destroy(data->shell.zxdg);
+
+ if (data->compositor)
+ wl_compositor_destroy(data->compositor);
+
+ if (data->registry)
+ wl_registry_destroy(data->registry);
+
+ if (data->display) {
+ WAYLAND_wl_display_flush(data->display);
+ WAYLAND_wl_display_disconnect(data->display);
+ }
+
+ SDL_free(data->classname);
+ SDL_free(data);
+ _this->driverdata = NULL;
+}
+
+#endif /* SDL_VIDEO_DRIVER_WAYLAND */
+
+/* vi: set ts=4 sw=4 expandtab: */