SDL  2.0
SDL_waylandvideo.c
Go to the documentation of this file.
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 #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 #define WAYLANDVID_DRIVER_NAME "wayland"
49 
50 /* Initialization/Query functions */
51 static int
52 Wayland_VideoInit(_THIS);
53 
54 static void
55 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
56 static int
57 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
58 
59 static void
60 Wayland_VideoQuit(_THIS);
61 
62 /* Find out what class name we should use
63  * Based on src/video/x11/SDL_x11video.c */
64 static char *
65 get_classname()
66 {
67  char *spot;
68 #if defined(__LINUX__) || defined(__FREEBSD__)
69  char procfile[1024];
70  char linkfile[1024];
71  int linksize;
72 #endif
73 
74  /* First allow environment variable override */
75  spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS");
76  if (spot) {
77  return SDL_strdup(spot);
78  } else {
79  /* Fallback to the "old" envvar */
80  spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
81  if (spot) {
82  return SDL_strdup(spot);
83  }
84  }
85 
86  /* Next look at the application's executable name */
87 #if defined(__LINUX__) || defined(__FREEBSD__)
88 #if defined(__LINUX__)
89  SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
90 #elif defined(__FREEBSD__)
91  SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
92  getpid());
93 #else
94 #error Where can we find the executable name?
95 #endif
96  linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
97  if (linksize > 0) {
98  linkfile[linksize] = '\0';
99  spot = SDL_strrchr(linkfile, '/');
100  if (spot) {
101  return SDL_strdup(spot + 1);
102  } else {
103  return SDL_strdup(linkfile);
104  }
105  }
106 #endif /* __LINUX__ || __FREEBSD__ */
107 
108  /* Finally use the default we've used forever */
109  return SDL_strdup("SDL_App");
110 }
111 
112 /* Wayland driver bootstrap functions */
113 static int
114 Wayland_Available(void)
115 {
116  struct wl_display *display = NULL;
117  if (SDL_WAYLAND_LoadSymbols()) {
118  display = WAYLAND_wl_display_connect(NULL);
119  if (display != NULL) {
120  WAYLAND_wl_display_disconnect(display);
121  }
123  }
124 
125  return (display != NULL);
126 }
127 
128 static void
129 Wayland_DeleteDevice(SDL_VideoDevice *device)
130 {
131  SDL_free(device);
133 }
134 
135 static SDL_VideoDevice *
136 Wayland_CreateDevice(int devindex)
137 {
139 
140  if (!SDL_WAYLAND_LoadSymbols()) {
141  return NULL;
142  }
143 
144  /* Initialize all variables that we clean on shutdown */
145  device = SDL_calloc(1, sizeof(SDL_VideoDevice));
146  if (!device) {
148  SDL_OutOfMemory();
149  return NULL;
150  }
151 
152  /* Set the function pointers */
153  device->VideoInit = Wayland_VideoInit;
154  device->VideoQuit = Wayland_VideoQuit;
155  device->SetDisplayMode = Wayland_SetDisplayMode;
156  device->GetDisplayModes = Wayland_GetDisplayModes;
158 
159  device->PumpEvents = Wayland_PumpEvents;
160 
170 
172  device->ShowWindow = Wayland_ShowWindow;
180 
184 
185 #if SDL_VIDEO_VULKAN
186  device->Vulkan_LoadLibrary = Wayland_Vulkan_LoadLibrary;
187  device->Vulkan_UnloadLibrary = Wayland_Vulkan_UnloadLibrary;
188  device->Vulkan_GetInstanceExtensions = Wayland_Vulkan_GetInstanceExtensions;
189  device->Vulkan_CreateSurface = Wayland_Vulkan_CreateSurface;
190 #endif
191 
192  device->free = Wayland_DeleteDevice;
193 
194  return device;
195 }
196 
198  WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
199  Wayland_Available, Wayland_CreateDevice
200 };
201 
202 static void
203 display_handle_geometry(void *data,
204  struct wl_output *output,
205  int x, int y,
206  int physical_width,
207  int physical_height,
208  int subpixel,
209  const char *make,
210  const char *model,
211  int transform)
212 
213 {
214  SDL_VideoDisplay *display = data;
215 
216  display->name = SDL_strdup(model);
217  display->driverdata = output;
218 }
219 
220 static void
221 display_handle_mode(void *data,
222  struct wl_output *output,
223  uint32_t flags,
224  int width,
225  int height,
226  int refresh)
227 {
228  SDL_VideoDisplay *display = data;
230 
231  SDL_zero(mode);
233  mode.w = width;
234  mode.h = height;
235  mode.refresh_rate = refresh / 1000; // mHz to Hz
236  SDL_AddDisplayMode(display, &mode);
237 
238  if (flags & WL_OUTPUT_MODE_CURRENT) {
239  display->current_mode = mode;
240  display->desktop_mode = mode;
241  }
242 }
243 
244 static void
245 display_handle_done(void *data,
246  struct wl_output *output)
247 {
248  SDL_VideoDisplay *display = data;
249  SDL_AddVideoDisplay(display);
250  SDL_free(display->name);
251  SDL_free(display);
252 }
253 
254 static void
255 display_handle_scale(void *data,
256  struct wl_output *output,
257  int32_t factor)
258 {
259  // TODO: do HiDPI stuff.
260 }
261 
262 static const struct wl_output_listener output_listener = {
263  display_handle_geometry,
264  display_handle_mode,
265  display_handle_done,
266  display_handle_scale
267 };
268 
269 static void
270 Wayland_add_display(SDL_VideoData *d, uint32_t id)
271 {
272  struct wl_output *output;
273  SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
274  if (!display) {
275  SDL_OutOfMemory();
276  return;
277  }
278  SDL_zero(*display);
279 
280  output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
281  if (!output) {
282  SDL_SetError("Failed to retrieve output.");
283  SDL_free(display);
284  return;
285  }
286 
287  wl_output_add_listener(output, &output_listener, display);
288 }
289 
290 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
291 static void
292 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
293  int32_t show_is_fullscreen)
294 {
295 }
296 
297 static void
298 windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
299 {
300  SDL_SendQuit();
301 }
302 
303 static const struct qt_windowmanager_listener windowmanager_listener = {
304  windowmanager_hints,
305  windowmanager_quit,
306 };
307 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
308 
309 static void
310 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
311  const char *interface, uint32_t version)
312 {
313  SDL_VideoData *d = data;
314 
315  if (strcmp(interface, "wl_compositor") == 0) {
317  } else if (strcmp(interface, "wl_output") == 0) {
318  Wayland_add_display(d, id);
319  } else if (strcmp(interface, "wl_seat") == 0) {
321  } else if (strcmp(interface, "wl_shell") == 0) {
323  } else if (strcmp(interface, "wl_shm") == 0) {
324  d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
325  d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
326  } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
328  } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
330  } else if (strcmp(interface, "wl_data_device_manager") == 0) {
332 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
333  } else if (strcmp(interface, "qt_touch_extension") == 0) {
334  Wayland_touch_create(d, id);
335  } else if (strcmp(interface, "qt_surface_extension") == 0) {
336  d->surface_extension = wl_registry_bind(registry, id,
337  &qt_surface_extension_interface, 1);
338  } else if (strcmp(interface, "qt_windowmanager") == 0) {
339  d->windowmanager = wl_registry_bind(registry, id,
340  &qt_windowmanager_interface, 1);
341  qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
342 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
343  }
344 }
345 
346 static const struct wl_registry_listener registry_listener = {
347  display_handle_global
348 };
349 
350 int
351 Wayland_VideoInit(_THIS)
352 {
353  SDL_VideoData *data = SDL_malloc(sizeof *data);
354  if (data == NULL)
355  return SDL_OutOfMemory();
356  memset(data, 0, sizeof *data);
357 
358  _this->driverdata = data;
359 
360  data->xkb_context = WAYLAND_xkb_context_new(0);
361  if (!data->xkb_context) {
362  return SDL_SetError("Failed to create XKB context");
363  }
364 
365  data->display = WAYLAND_wl_display_connect(NULL);
366  if (data->display == NULL) {
367  return SDL_SetError("Failed to connect to a Wayland display");
368  }
369 
371  if (data->registry == NULL) {
372  return SDL_SetError("Failed to get the Wayland registry");
373  }
374 
375  wl_registry_add_listener(data->registry, &registry_listener, data);
376 
377  // First roundtrip to receive all registry objects.
378  WAYLAND_wl_display_roundtrip(data->display);
379 
380  // Second roundtrip to receive all output events.
381  WAYLAND_wl_display_roundtrip(data->display);
382 
383  Wayland_InitMouse();
384 
385  /* Get the surface class name, usually the name of the application */
386  data->classname = get_classname();
387 
388  WAYLAND_wl_display_flush(data->display);
389 
390  return 0;
391 }
392 
393 static void
394 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
395 {
396  // Nothing to do here, everything was already done in the wl_output
397  // callbacks.
398 }
399 
400 static int
401 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
402 {
403  return SDL_Unsupported();
404 }
405 
406 void
407 Wayland_VideoQuit(_THIS)
408 {
409  SDL_VideoData *data = _this->driverdata;
410  int i;
411 
412  Wayland_FiniMouse ();
413 
414  for (i = 0; i < _this->num_displays; ++i) {
415  SDL_VideoDisplay *display = &_this->displays[i];
416  wl_output_destroy(display->driverdata);
417  display->driverdata = NULL;
418  }
419 
423 
424  if (data->xkb_context) {
425  WAYLAND_xkb_context_unref(data->xkb_context);
426  data->xkb_context = NULL;
427  }
428 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
429  if (data->windowmanager)
430  qt_windowmanager_destroy(data->windowmanager);
431 
432  if (data->surface_extension)
433  qt_surface_extension_destroy(data->surface_extension);
434 
435  Wayland_touch_destroy(data);
436 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
437 
438  if (data->shm)
439  wl_shm_destroy(data->shm);
440 
441  if (data->cursor_theme)
442  WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
443 
444  if (data->shell)
445  wl_shell_destroy(data->shell);
446 
447  if (data->compositor)
449 
450  if (data->registry)
452 
453  if (data->display) {
454  WAYLAND_wl_display_flush(data->display);
455  WAYLAND_wl_display_disconnect(data->display);
456  }
457 
458  SDL_free(data->classname);
459  SDL_free(data);
460  _this->driverdata = NULL;
461 }
462 
463 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
464 
465 /* vi: set ts=4 sw=4 expandtab: */
int(* Vulkan_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:270
static void wl_registry_destroy(struct wl_registry *wl_registry)
static struct wl_registry * wl_display_get_registry(struct wl_display *wl_display)
void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
void Wayland_SetWindowSize(_THIS, SDL_Window *window)
void(* RestoreWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:227
const struct wl_interface wl_shm_interface
void Wayland_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *_display, SDL_bool fullscreen)
void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
void SDL_WAYLAND_UnloadSymbols(void)
char * Wayland_GetClipboardText(_THIS)
int(* SetWindowHitTest)(SDL_Window *window, SDL_bool enabled)
Definition: SDL_sysvideo.h:305
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
signed int int32_t
int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
struct wl_display * display
void Wayland_MaximizeWindow(_THIS, SDL_Window *window)
VideoBootStrap Wayland_bootstrap
void Wayland_GLES_DeleteContext(_THIS, SDL_GLContext context)
void(* free)(_THIS)
Definition: SDL_sysvideo.h:390
void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
int Wayland_SetClipboardText(_THIS, const char *text)
static void wl_shell_destroy(struct wl_shell *wl_shell)
#define Wayland_GLES_UnloadLibrary
static void * wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:260
void(* ShowWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:222
The structure that defines a display mode.
Definition: SDL_video.h:53
#define memset
Definition: SDL_malloc.c:639
void Wayland_ShowWindow(_THIS, SDL_Window *window)
void(* SetWindowSize)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:215
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
#define Wayland_GLES_GetSwapInterval
struct wl_cursor_theme * cursor_theme
int Wayland_CreateWindow(_THIS, SDL_Window *window)
const struct wl_interface wl_output_interface
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:254
static void wl_compositor_destroy(struct wl_compositor *wl_compositor)
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:204
SDL_GLContext Wayland_GLES_CreateContext(_THIS, SDL_Window *window)
void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_bool(* Vulkan_GetInstanceExtensions)(_THIS, SDL_Window *window, unsigned *count, const char **names)
Definition: SDL_sysvideo.h:272
void * SDL_calloc(size_t nmemb, size_t size)
#define Wayland_GLES_SetSwapInterval
SDL_bool(* GetWindowWMInfo)(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
Definition: SDL_sysvideo.h:247
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:257
struct wl_data_device_manager * data_device_manager
void Wayland_SetWindowTitle(_THIS, SDL_Window *window)
void Wayland_DestroyWindow(_THIS, SDL_Window *window)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
SDL_bool(* Vulkan_CreateSurface)(_THIS, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface)
Definition: SDL_sysvideo.h:273
#define _THIS
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:258
void SDL_free(void *mem)
void(* Vulkan_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:271
static void wl_shm_destroy(struct wl_shm *wl_shm)
struct xkb_context * xkb_context
int SDL_WAYLAND_LoadSymbols(void)
SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *info)
struct wl_shell * shell
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
GLenum mode
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:312
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:234
#define SDL_zero(x)
Definition: SDL_stdinc.h:369
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int Wayland_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context)
void Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
#define SDL_getenv
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:256
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
void(* GetDisplayModes)(_THIS, SDL_VideoDisplay *display)
Definition: SDL_sysvideo.h:196
int Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
#define Wayland_GLES_GetProcAddress
static int wl_output_add_listener(struct wl_output *wl_output, const struct wl_output_listener *listener, void *data)
static void wl_output_destroy(struct wl_output *wl_output)
#define NULL
Definition: begin_code.h:164
int(* CreateSDLWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:210
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
unsigned int uint32_t
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:166
#define SDL_SetError
const struct wl_interface wl_compositor_interface
GLbitfield flags
struct wl_compositor * compositor
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
void Wayland_RestoreWindow(_THIS, SDL_Window *window)
const struct wl_interface wl_shell_interface
void Wayland_display_destroy_input(SDL_VideoData *d)
void Wayland_PumpEvents(_THIS)
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:262
#define SDL_strdup
GLuint GLenum GLenum transform
struct wl_registry * registry
SDL_bool Wayland_HasClipboardText(_THIS)
SDL_bool(* HasClipboardText)(_THIS)
Definition: SDL_sysvideo.h:299
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:160
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
void(* SetWindowFullscreen)(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
Definition: SDL_sysvideo.h:230
#define SDL_malloc
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:263
char *(* GetClipboardText)(_THIS)
Definition: SDL_sysvideo.h:298
Uint32 format
Definition: SDL_video.h:55
void(* SetWindowTitle)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:212
const struct wl_interface wl_data_device_manager_interface
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:261
void(* MaximizeWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:225
int(* SetClipboardText)(_THIS, const char *text)
Definition: SDL_sysvideo.h:297
int Wayland_GLES_LoadLibrary(_THIS, const char *path)
struct wl_shm * shm
#define SDL_strrchr
#define SDL_Unsupported()
Definition: SDL_error.h:53
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:255
int SDL_SendQuit(void)
Definition: SDL_quit.c:137
static int wl_registry_add_listener(struct wl_registry *wl_registry, const struct wl_registry_listener *listener, void *data)
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:280