change SDL 1.2 to SDL 2.0
[platform/upstream/SDL.git] / src / video / wayland / SDL_waylandvideo.c
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;
63     if (SDL_WAYLAND_LoadSymbols()) {
64         display = WAYLAND_wl_display_connect(NULL);
65         if (display != NULL) {
66             WAYLAND_wl_display_disconnect(display);
67         }
68         SDL_WAYLAND_UnloadSymbols();
69     }
70
71     return (display != NULL);
72 }
73
74 static void
75 Wayland_DeleteDevice(SDL_VideoDevice *device)
76 {
77     SDL_free(device);
78     SDL_WAYLAND_UnloadSymbols();
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) {
93         SDL_WAYLAND_UnloadSymbols();
94         SDL_OutOfMemory();
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;
103     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
104
105     device->PumpEvents = Wayland_PumpEvents;
106
107     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
108     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
109     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
110     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
111     device->GL_CreateContext = Wayland_GLES_CreateContext;
112     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
113     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
114     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
115     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
116
117     device->CreateWindow = Wayland_CreateWindow;
118     device->ShowWindow = Wayland_ShowWindow;
119     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
120     device->SetWindowSize = Wayland_SetWindowSize;
121     device->DestroyWindow = Wayland_DestroyWindow;
122     device->SetWindowHitTest = Wayland_SetWindowHitTest;
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;
161     SDL_DisplayMode mode;
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) {
250         Wayland_display_add_input(d, id);
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
343     Wayland_display_destroy_input(data);
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: */