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 <fcntl.h>
39 #include <xkbcommon/xkbcommon.h>
40 
41 #include "SDL_waylanddyn.h"
42 #include <wayland-util.h>
43 
44 #define WAYLANDVID_DRIVER_NAME "wayland"
45 
46 /* Initialization/Query functions */
47 static int
48 Wayland_VideoInit(_THIS);
49 
50 static void
51 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
52 static int
53 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
54 
55 static void
56 Wayland_VideoQuit(_THIS);
57 
58 /* Wayland driver bootstrap functions */
59 static int
60 Wayland_Available(void)
61 {
62  struct wl_display *display = NULL;
64  display = WAYLAND_wl_display_connect(NULL);
65  if (display != NULL) {
66  WAYLAND_wl_display_disconnect(display);
67  }
69  }
70 
71  return (display != NULL);
72 }
73 
74 static void
75 Wayland_DeleteDevice(SDL_VideoDevice *device)
76 {
77  SDL_free(device);
79 }
80 
81 static SDL_VideoDevice *
82 Wayland_CreateDevice(int devindex)
83 {
84  SDL_VideoDevice *device;
85 
86  if (!SDL_WAYLAND_LoadSymbols()) {
87  return NULL;
88  }
89 
90  /* Initialize all variables that we clean on shutdown */
91  device = SDL_calloc(1, sizeof(SDL_VideoDevice));
92  if (!device) {
95  return NULL;
96  }
97 
98  /* Set the function pointers */
99  device->VideoInit = Wayland_VideoInit;
100  device->VideoQuit = Wayland_VideoQuit;
101  device->SetDisplayMode = Wayland_SetDisplayMode;
102  device->GetDisplayModes = Wayland_GetDisplayModes;
104 
105  device->PumpEvents = Wayland_PumpEvents;
106 
116 
118  device->ShowWindow = Wayland_ShowWindow;
123 
124  device->free = Wayland_DeleteDevice;
125 
126  return device;
127 }
128 
129 VideoBootStrap Wayland_bootstrap = {
130  WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
131  Wayland_Available, Wayland_CreateDevice
132 };
133 
134 static void
135 display_handle_geometry(void *data,
136  struct wl_output *output,
137  int x, int y,
138  int physical_width,
139  int physical_height,
140  int subpixel,
141  const char *make,
142  const char *model,
143  int transform)
144 
145 {
146  SDL_VideoDisplay *display = data;
147 
148  display->name = strdup(model);
149  display->driverdata = output;
150 }
151 
152 static void
153 display_handle_mode(void *data,
154  struct wl_output *output,
155  uint32_t flags,
156  int width,
157  int height,
158  int refresh)
159 {
160  SDL_VideoDisplay *display = data;
162 
163  SDL_zero(mode);
164  mode.w = width;
165  mode.h = height;
166  mode.refresh_rate = refresh / 1000; // mHz to Hz
167  SDL_AddDisplayMode(display, &mode);
168 
169  if (flags & WL_OUTPUT_MODE_CURRENT) {
170  display->current_mode = mode;
171  display->desktop_mode = mode;
172  }
173 }
174 
175 static void
176 display_handle_done(void *data,
177  struct wl_output *output)
178 {
179  SDL_VideoDisplay *display = data;
180  SDL_AddVideoDisplay(display);
181  SDL_free(display->name);
182  SDL_free(display);
183 }
184 
185 static void
186 display_handle_scale(void *data,
187  struct wl_output *output,
188  int32_t factor)
189 {
190  // TODO: do HiDPI stuff.
191 }
192 
193 static const struct wl_output_listener output_listener = {
194  display_handle_geometry,
195  display_handle_mode,
196  display_handle_done,
197  display_handle_scale
198 };
199 
200 static void
201 Wayland_add_display(SDL_VideoData *d, uint32_t id)
202 {
203  struct wl_output *output;
204  SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
205  if (!display) {
206  SDL_OutOfMemory();
207  return;
208  }
209  SDL_zero(*display);
210 
211  output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
212  if (!output) {
213  SDL_SetError("Failed to retrieve output.");
214  return;
215  }
216 
217  wl_output_add_listener(output, &output_listener, display);
218 }
219 
220 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
221 static void
222 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
223  int32_t show_is_fullscreen)
224 {
225 }
226 
227 static void
228 windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
229 {
230  SDL_SendQuit();
231 }
232 
233 static const struct qt_windowmanager_listener windowmanager_listener = {
234  windowmanager_hints,
235  windowmanager_quit,
236 };
237 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
238 
239 static void
240 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
241  const char *interface, uint32_t version)
242 {
243  SDL_VideoData *d = data;
244 
245  if (strcmp(interface, "wl_compositor") == 0) {
246  d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
247  } else if (strcmp(interface, "wl_output") == 0) {
248  Wayland_add_display(d, id);
249  } else if (strcmp(interface, "wl_seat") == 0) {
251  } else if (strcmp(interface, "wl_shell") == 0) {
252  d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
253  } else if (strcmp(interface, "wl_shm") == 0) {
254  d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
255  d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
256  d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
257 
258 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
259  } else if (strcmp(interface, "qt_touch_extension") == 0) {
260  Wayland_touch_create(d, id);
261  } else if (strcmp(interface, "qt_surface_extension") == 0) {
262  d->surface_extension = wl_registry_bind(registry, id,
263  &qt_surface_extension_interface, 1);
264  } else if (strcmp(interface, "qt_windowmanager") == 0) {
265  d->windowmanager = wl_registry_bind(registry, id,
266  &qt_windowmanager_interface, 1);
267  qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
268 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
269  }
270 }
271 
272 static const struct wl_registry_listener registry_listener = {
273  display_handle_global
274 };
275 
276 int
277 Wayland_VideoInit(_THIS)
278 {
279  SDL_VideoData *data = SDL_malloc(sizeof *data);
280  if (data == NULL)
281  return SDL_OutOfMemory();
282  memset(data, 0, sizeof *data);
283 
284  _this->driverdata = data;
285 
286  data->display = WAYLAND_wl_display_connect(NULL);
287  if (data->display == NULL) {
288  return SDL_SetError("Failed to connect to a Wayland display");
289  }
290 
291  data->registry = wl_display_get_registry(data->display);
292  if (data->registry == NULL) {
293  return SDL_SetError("Failed to get the Wayland registry");
294  }
295 
296  wl_registry_add_listener(data->registry, &registry_listener, data);
297 
298  // First roundtrip to receive all registry objects.
299  WAYLAND_wl_display_roundtrip(data->display);
300 
301  // Second roundtrip to receive all output events.
302  WAYLAND_wl_display_roundtrip(data->display);
303 
304  data->xkb_context = WAYLAND_xkb_context_new(0);
305  if (!data->xkb_context) {
306  return SDL_SetError("Failed to create XKB context");
307  }
308 
309  Wayland_InitMouse();
310 
311  WAYLAND_wl_display_flush(data->display);
312 
313  return 0;
314 }
315 
316 static void
317 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
318 {
319  // Nothing to do here, everything was already done in the wl_output
320  // callbacks.
321 }
322 
323 static int
324 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
325 {
326  return SDL_Unsupported();
327 }
328 
329 void
330 Wayland_VideoQuit(_THIS)
331 {
332  SDL_VideoData *data = _this->driverdata;
333  int i;
334 
335  Wayland_FiniMouse ();
336 
337  for (i = 0; i < _this->num_displays; ++i) {
338  SDL_VideoDisplay *display = &_this->displays[i];
339  wl_output_destroy(display->driverdata);
340  display->driverdata = NULL;
341  }
342 
344 
345  if (data->xkb_context) {
346  WAYLAND_xkb_context_unref(data->xkb_context);
347  data->xkb_context = NULL;
348  }
349 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
350  if (data->windowmanager)
351  qt_windowmanager_destroy(data->windowmanager);
352 
353  if (data->surface_extension)
354  qt_surface_extension_destroy(data->surface_extension);
355 
356  Wayland_touch_destroy(data);
357 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
358 
359  if (data->shm)
360  wl_shm_destroy(data->shm);
361 
362  if (data->cursor_theme)
363  WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
364 
365  if (data->shell)
366  wl_shell_destroy(data->shell);
367 
368  if (data->compositor)
369  wl_compositor_destroy(data->compositor);
370 
371  if (data->registry)
372  wl_registry_destroy(data->registry);
373 
374  if (data->display) {
375  WAYLAND_wl_display_flush(data->display);
376  WAYLAND_wl_display_disconnect(data->display);
377  }
378 
379  free(data);
380  _this->driverdata = NULL;
381 }
382 
383 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
384 
385 /* vi: set ts=4 sw=4 expandtab: */
void Wayland_SetWindowSize(_THIS, SDL_Window *window)
void Wayland_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *_display, SDL_bool fullscreen)
void SDL_WAYLAND_UnloadSymbols(void)
int(* SetWindowHitTest)(SDL_Window *window, SDL_bool enabled)
Definition: SDL_sysvideo.h:274
signed int int32_t
int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
struct wl_display * display
void Wayland_GLES_DeleteContext(_THIS, SDL_GLContext context)
void(* free)(_THIS)
Definition: SDL_sysvideo.h:345
SDL_EventEntry * free
Definition: SDL_events.c:81
#define Wayland_GLES_UnloadLibrary
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:240
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:203
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:200
GLint GLint GLsizei width
Definition: SDL_opengl.h:1565
#define Wayland_GLES_GetSwapInterval
struct wl_cursor_theme * cursor_theme
void(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:242
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
int Wayland_CreateWindow(_THIS, SDL_Window *window)
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:593
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:234
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:189
SDL_GLContext Wayland_GLES_CreateContext(_THIS, SDL_Window *window)
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
void * SDL_calloc(size_t nmemb, size_t size)
#define Wayland_GLES_SetSwapInterval
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
SDL_bool(* GetWindowWMInfo)(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
Definition: SDL_sysvideo.h:227
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:237
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
#define _THIS
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:238
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:127
GLenum mode
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:280
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:214
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
int Wayland_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context)
void Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:236
struct wl_cursor * default_cursor
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:42
void(* GetDisplayModes)(_THIS, SDL_VideoDisplay *display)
Definition: SDL_sysvideo.h:181
#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:126
unsigned int uint32_t
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:161
#define SDL_SetError
struct wl_compositor * compositor
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
void Wayland_display_destroy_input(SDL_VideoData *d)
void Wayland_PumpEvents(_THIS)
int(* CreateWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:195
GLuint GLenum GLenum transform
struct wl_registry * registry
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:709
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:155
GLbitfield flags
void(* SetWindowFullscreen)(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
Definition: SDL_sysvideo.h:210
#define SDL_malloc
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:243
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:241
int Wayland_GLES_LoadLibrary(_THIS, const char *path)
void Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
struct wl_shm * shm
#define SDL_Unsupported()
Definition: SDL_error.h:53
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:235
int SDL_SendQuit(void)
Definition: SDL_quit.c:139
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:249