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