change SDL 1.2 to SDL 2.0
[platform/upstream/SDL.git] / src / video / wayland / SDL_waylandevents.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_stdinc.h"
27 #include "SDL_assert.h"
28
29 #include "../../events/SDL_sysevents.h"
30 #include "../../events/SDL_events_c.h"
31 #include "../../events/scancodes_xfree86.h"
32
33 #include "SDL_waylandvideo.h"
34 #include "SDL_waylandevents_c.h"
35 #include "SDL_waylandwindow.h"
36
37 #include "SDL_waylanddyn.h"
38
39 #include <linux/input.h>
40 #include <sys/select.h>
41 #include <sys/mman.h>
42 #include <poll.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <xkbcommon/xkbcommon.h>
46
47 struct SDL_WaylandInput {
48     SDL_VideoData *display;
49     struct wl_seat *seat;
50     struct wl_pointer *pointer;
51     struct wl_keyboard *keyboard;
52     SDL_WindowData *pointer_focus;
53     SDL_WindowData *keyboard_focus;
54
55     /* Last motion location */
56     wl_fixed_t sx_w;
57     wl_fixed_t sy_w;
58     
59     struct {
60         struct xkb_keymap *keymap;
61         struct xkb_state *state;
62     } xkb;
63 };
64
65 void
66 Wayland_PumpEvents(_THIS)
67 {
68     SDL_VideoData *d = _this->driverdata;
69     struct pollfd pfd[1];
70
71     pfd[0].fd = WAYLAND_wl_display_get_fd(d->display);
72     pfd[0].events = POLLIN;
73     poll(pfd, 1, 0);
74
75     if (pfd[0].revents & POLLIN)
76         WAYLAND_wl_display_dispatch(d->display);
77     else
78         WAYLAND_wl_display_dispatch_pending(d->display);
79 }
80
81 static void
82 pointer_handle_enter(void *data, struct wl_pointer *pointer,
83                      uint32_t serial, struct wl_surface *surface,
84                      wl_fixed_t sx_w, wl_fixed_t sy_w)
85 {
86     struct SDL_WaylandInput *input = data;
87     SDL_WindowData *window;
88
89     if (!surface) {
90         /* enter event for a window we've just destroyed */
91         return;
92     }
93     
94     /* This handler will be called twice in Wayland 1.4
95      * Once for the window surface which has valid user data
96      * and again for the mouse cursor surface which does not have valid user data
97      * We ignore the later
98      */
99
100     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
101     
102     if (window) {
103         input->pointer_focus = window;
104         SDL_SetMouseFocus(window->sdlwindow);
105     }
106 }
107
108 static void
109 pointer_handle_leave(void *data, struct wl_pointer *pointer,
110                      uint32_t serial, struct wl_surface *surface)
111 {
112     struct SDL_WaylandInput *input = data;
113
114     if (input->pointer_focus) {
115         SDL_SetMouseFocus(NULL);
116         input->pointer_focus = NULL;
117     }
118 }
119
120 static void
121 pointer_handle_motion(void *data, struct wl_pointer *pointer,
122                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
123 {
124     struct SDL_WaylandInput *input = data;
125     SDL_WindowData *window = input->pointer_focus;
126     input->sx_w = sx_w;
127     input->sy_w = sy_w;
128     if (input->pointer_focus) {
129         const int sx = wl_fixed_to_int(sx_w);
130         const int sy = wl_fixed_to_int(sy_w);
131         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
132     }
133 }
134
135 static SDL_bool
136 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
137 {
138     SDL_WindowData *window_data = input->pointer_focus;
139     SDL_Window *window = window_data->sdlwindow;
140
141     if (window->hit_test) {
142         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
143         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
144         static const uint32_t directions[] = {
145             WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
146             WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
147             WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
148             WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
149         };
150         switch (rc) {
151             case SDL_HITTEST_DRAGGABLE:
152                 wl_shell_surface_move(window_data->shell_surface, input->seat, serial);
153                 return SDL_TRUE;
154
155             case SDL_HITTEST_RESIZE_TOPLEFT:
156             case SDL_HITTEST_RESIZE_TOP:
157             case SDL_HITTEST_RESIZE_TOPRIGHT:
158             case SDL_HITTEST_RESIZE_RIGHT:
159             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
160             case SDL_HITTEST_RESIZE_BOTTOM:
161             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
162             case SDL_HITTEST_RESIZE_LEFT:
163                 wl_shell_surface_resize(window_data->shell_surface, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
164                 return SDL_TRUE;
165
166             default: return SDL_FALSE;
167         }
168     }
169
170     return SDL_FALSE;
171 }
172
173 static void
174 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
175                       uint32_t time, uint32_t button, uint32_t state_w)
176 {
177     struct SDL_WaylandInput *input = data;
178     SDL_WindowData *window = input->pointer_focus;
179     enum wl_pointer_button_state state = state_w;
180     uint32_t sdl_button;
181     
182     if  (input->pointer_focus) {
183         switch (button) {
184             case BTN_LEFT:
185                 sdl_button = SDL_BUTTON_LEFT;
186                 if (ProcessHitTest(data, serial)) {
187                     return;  /* don't pass this event on to app. */
188                 }
189                 break;
190             case BTN_MIDDLE:
191                 sdl_button = SDL_BUTTON_MIDDLE;
192                 break;
193             case BTN_RIGHT:
194                 sdl_button = SDL_BUTTON_RIGHT;
195                 break;
196             case BTN_SIDE:
197                 sdl_button = SDL_BUTTON_X1;
198                 break;
199             case BTN_EXTRA:
200                 sdl_button = SDL_BUTTON_X2;
201                 break;
202             default:
203                 return;
204         }
205
206         SDL_SendMouseButton(window->sdlwindow, 0,
207                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
208     }
209 }
210
211 static void
212 pointer_handle_axis(void *data, struct wl_pointer *pointer,
213                     uint32_t time, uint32_t axis, wl_fixed_t value)
214 {
215     struct SDL_WaylandInput *input = data;
216     SDL_WindowData *window = input->pointer_focus;
217     enum wl_pointer_axis a = axis;
218     int x, y;
219
220     if (input->pointer_focus) {
221         switch (a) {
222             case WL_POINTER_AXIS_VERTICAL_SCROLL:
223                 x = 0;
224                 y = wl_fixed_to_int(value);
225                 break;
226             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
227                 x = wl_fixed_to_int(value);
228                 y = 0;
229                 break;
230             default:
231                 return;
232         }
233
234         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
235     }
236 }
237
238 static const struct wl_pointer_listener pointer_listener = {
239     pointer_handle_enter,
240     pointer_handle_leave,
241     pointer_handle_motion,
242     pointer_handle_button,
243     pointer_handle_axis,
244 };
245
246 static void
247 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
248                        uint32_t format, int fd, uint32_t size)
249 {
250     struct SDL_WaylandInput *input = data;
251     char *map_str;
252
253     if (!data) {
254         close(fd);
255         return;
256     }
257
258     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
259         close(fd);
260         return;
261     }
262
263     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
264     if (map_str == MAP_FAILED) {
265         close(fd);
266         return;
267     }
268
269     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
270                                                 map_str,
271                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
272                                                 0);
273     munmap(map_str, size);
274     close(fd);
275
276     if (!input->xkb.keymap) {
277         fprintf(stderr, "failed to compile keymap\n");
278         return;
279     }
280
281     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
282     if (!input->xkb.state) {
283         fprintf(stderr, "failed to create XKB state\n");
284         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
285         input->xkb.keymap = NULL;
286         return;
287     }
288 }
289
290 static void
291 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
292                       uint32_t serial, struct wl_surface *surface,
293                       struct wl_array *keys)
294 {
295     struct SDL_WaylandInput *input = data;
296     SDL_WindowData *window;
297
298     if (!surface) {
299         /* enter event for a window we've just destroyed */
300         return;
301     }
302  
303     window = wl_surface_get_user_data(surface);
304
305     input->keyboard_focus = window;
306     window->keyboard_device = input;
307     if (window) {
308         SDL_SetKeyboardFocus(window->sdlwindow);
309     }
310 }
311
312 static void
313 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
314                       uint32_t serial, struct wl_surface *surface)
315 {
316     SDL_SetKeyboardFocus(NULL);
317 }
318
319 static void
320 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
321                     uint32_t serial, uint32_t time, uint32_t key,
322                     uint32_t state_w)
323 {
324     struct SDL_WaylandInput *input = data;
325     SDL_WindowData *window = input->keyboard_focus;
326     enum wl_keyboard_key_state state = state_w;
327     const xkb_keysym_t *syms;
328     uint32_t scancode;
329     char text[8];
330     int size;
331
332     if (key < SDL_arraysize(xfree86_scancode_table2)) {
333         scancode = xfree86_scancode_table2[key];
334
335         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
336         if (scancode != SDL_SCANCODE_UNKNOWN)
337             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
338                                 SDL_PRESSED : SDL_RELEASED, scancode);
339     }
340
341     if (!window || window->keyboard_device != input || !input->xkb.state)
342         return;
343
344     // TODO can this happen?
345     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
346         return;
347
348     if (state) {
349         size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
350
351         if (size > 0) {
352             text[size] = 0;
353             SDL_SendKeyboardText(text);
354         }
355     }
356 }
357
358 static void
359 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
360                           uint32_t serial, uint32_t mods_depressed,
361                           uint32_t mods_latched, uint32_t mods_locked,
362                           uint32_t group)
363 {
364     struct SDL_WaylandInput *input = data;
365
366     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
367                           mods_locked, 0, 0, group);
368 }
369
370 static const struct wl_keyboard_listener keyboard_listener = {
371     keyboard_handle_keymap,
372     keyboard_handle_enter,
373     keyboard_handle_leave,
374     keyboard_handle_key,
375     keyboard_handle_modifiers,
376 };
377
378 static void
379 seat_handle_capabilities(void *data, struct wl_seat *seat,
380                          enum wl_seat_capability caps)
381 {
382     struct SDL_WaylandInput *input = data;
383
384     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
385         input->pointer = wl_seat_get_pointer(seat);
386         input->display->pointer = input->pointer;
387         wl_pointer_set_user_data(input->pointer, input);
388         wl_pointer_add_listener(input->pointer, &pointer_listener,
389                                 input);
390     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
391         wl_pointer_destroy(input->pointer);
392         input->pointer = NULL;
393     }
394
395     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
396         input->keyboard = wl_seat_get_keyboard(seat);
397         wl_keyboard_set_user_data(input->keyboard, input);
398         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
399                                  input);
400     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
401         wl_keyboard_destroy(input->keyboard);
402         input->keyboard = NULL;
403     }
404 }
405
406 static const struct wl_seat_listener seat_listener = {
407     seat_handle_capabilities,
408 };
409
410 void
411 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
412 {
413     struct SDL_WaylandInput *input;
414
415     input = SDL_calloc(1, sizeof *input);
416     if (input == NULL)
417         return;
418
419     input->display = d;
420     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
421     input->sx_w = wl_fixed_from_int(0);
422     input->sy_w = wl_fixed_from_int(0);
423     d->input = input;
424
425     wl_seat_add_listener(input->seat, &seat_listener, input);
426     wl_seat_set_user_data(input->seat, input);
427
428     WAYLAND_wl_display_flush(d->display);
429 }
430
431 void Wayland_display_destroy_input(SDL_VideoData *d)
432 {
433     struct SDL_WaylandInput *input = d->input;
434
435     if (!input)
436         return;
437
438     if (input->keyboard)
439         wl_keyboard_destroy(input->keyboard);
440
441     if (input->pointer)
442         wl_pointer_destroy(input->pointer);
443
444     if (input->seat)
445         wl_seat_destroy(input->seat);
446
447     if (input->xkb.state)
448         WAYLAND_xkb_state_unref(input->xkb.state);
449
450     if (input->xkb.keymap)
451         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
452
453     SDL_free(input);
454     d->input = NULL;
455 }
456
457 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
458
459 /* vi: set ts=4 sw=4 expandtab: */