src/video/wayland/SDL_waylandevents.c
author Gabriel Jacobo
Sat, 14 Dec 2013 20:18:43 -0300
changeset 8062 4fc5f66d63cc
child 8104 2e4f1bd21196
permissions -rw-r--r--
Wayland support

Based on the original port to Wayland by: Joel Teichroeb, Benjamin Franzke, Scott Moreau, et al.

Additional changes in this commit, done by me:

* Wayland uses the common EGL framework
* EGL can now create a desktop OpenGL context
* testgl2 loads GL functions dynamically, no need to link to libGL anymore
* Assorted fixes to the Wayland backend

Tested on the Weston Compositor (v1.0.5) that ships with Ubuntu 13.10,
running Weston under X. Tests ran: testrendercopyex (all backends), testgl2, testgles2,testintersections
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.h"
    23 
    24 #include "SDL_stdinc.h"
    25 #include "SDL_assert.h"
    26 
    27 #include "../../events/SDL_sysevents.h"
    28 #include "../../events/SDL_events_c.h"
    29 #include "../../events/scancodes_xfree86.h"
    30 
    31 #include "SDL_waylandvideo.h"
    32 #include "SDL_waylandevents_c.h"
    33 #include "SDL_waylandwindow.h"
    34 
    35 #include <linux/input.h>
    36 #include <sys/select.h>
    37 #include <sys/mman.h>
    38 #include <poll.h>
    39 #include <errno.h>
    40 #include <unistd.h>
    41 #include <xkbcommon/xkbcommon.h>
    42 
    43 struct SDL_WaylandInput {
    44     SDL_VideoData *display;
    45     struct wl_seat *seat;
    46     struct wl_pointer *pointer;
    47     struct wl_keyboard *keyboard;
    48     SDL_WindowData *pointer_focus;
    49     SDL_WindowData *keyboard_focus;
    50 
    51     struct {
    52         struct xkb_keymap *keymap;
    53         struct xkb_state *state;
    54     } xkb;
    55 };
    56 
    57 void
    58 Wayland_PumpEvents(_THIS)
    59 {
    60     SDL_VideoData *d = _this->driverdata;
    61     struct pollfd pfd[1];
    62 
    63     pfd[0].fd = wl_display_get_fd(d->display);
    64     pfd[0].events = POLLIN;
    65     poll(pfd, 1, 0);
    66 
    67     if (pfd[0].revents & POLLIN)
    68         wl_display_dispatch(d->display);
    69     else
    70         wl_display_dispatch_pending(d->display);
    71 }
    72 
    73 static void
    74 pointer_handle_enter(void *data, struct wl_pointer *pointer,
    75                      uint32_t serial, struct wl_surface *surface,
    76                      wl_fixed_t sx_w, wl_fixed_t sy_w)
    77 {
    78     struct SDL_WaylandInput *input = data;
    79     SDL_WindowData *window;
    80 
    81     if (!surface) {
    82         /* enter event for a window we've just destroyed */
    83         return;
    84     }
    85 
    86     input->pointer_focus = wl_surface_get_user_data(surface);
    87     window = input->pointer_focus;
    88     SDL_SetMouseFocus(window->sdlwindow);
    89 }
    90 
    91 static void
    92 pointer_handle_leave(void *data, struct wl_pointer *pointer,
    93                      uint32_t serial, struct wl_surface *surface)
    94 {
    95     struct SDL_WaylandInput *input = data;
    96 
    97     SDL_SetMouseFocus(NULL);
    98     input->pointer_focus = NULL;
    99 }
   100 
   101 static void
   102 pointer_handle_motion(void *data, struct wl_pointer *pointer,
   103                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
   104 {
   105     struct SDL_WaylandInput *input = data;
   106     SDL_WindowData *window = input->pointer_focus;
   107     int sx = wl_fixed_to_int(sx_w);
   108     int sy = wl_fixed_to_int(sy_w);
   109 
   110     SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
   111 }
   112 
   113 static void
   114 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
   115                       uint32_t time, uint32_t button, uint32_t state_w)
   116 {
   117     struct SDL_WaylandInput *input = data;
   118     SDL_WindowData *window = input->pointer_focus;
   119     enum wl_pointer_button_state state = state_w;
   120     uint32_t sdl_button;
   121 
   122     switch (button) {
   123     case BTN_LEFT:
   124         sdl_button = SDL_BUTTON_LEFT;
   125         break;
   126     case BTN_MIDDLE:
   127         sdl_button = SDL_BUTTON_MIDDLE;
   128         break;
   129     case BTN_RIGHT:
   130         sdl_button = SDL_BUTTON_RIGHT;
   131         break;
   132     case BTN_SIDE:
   133         sdl_button = SDL_BUTTON_X1;
   134         break;
   135     case BTN_EXTRA:
   136         sdl_button = SDL_BUTTON_X2;
   137         break;
   138     default:
   139         return;
   140     }
   141 
   142     SDL_SendMouseButton(window->sdlwindow, 0,
   143                         state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   144 }
   145 
   146 static void
   147 pointer_handle_axis(void *data, struct wl_pointer *pointer,
   148                     uint32_t time, uint32_t axis, wl_fixed_t value)
   149 {
   150     struct SDL_WaylandInput *input = data;
   151     SDL_WindowData *window = input->pointer_focus;
   152     enum wl_pointer_axis a = axis;
   153     int x, y;
   154 
   155     switch (a) {
   156     case WL_POINTER_AXIS_VERTICAL_SCROLL:
   157         x = 0;
   158         y = wl_fixed_to_int(value);
   159         break;
   160     case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
   161         x = wl_fixed_to_int(value);
   162         y = 0;
   163         break;
   164     default:
   165         return;
   166     }
   167 
   168     SDL_SendMouseWheel(window->sdlwindow, 0, x, y);
   169 }
   170 
   171 static const struct wl_pointer_listener pointer_listener = {
   172     pointer_handle_enter,
   173     pointer_handle_leave,
   174     pointer_handle_motion,
   175     pointer_handle_button,
   176     pointer_handle_axis,
   177 };
   178 
   179 static void
   180 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
   181                        uint32_t format, int fd, uint32_t size)
   182 {
   183     struct SDL_WaylandInput *input = data;
   184     char *map_str;
   185 
   186     if (!data) {
   187         close(fd);
   188         return;
   189     }
   190 
   191     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
   192         close(fd);
   193         return;
   194     }
   195 
   196     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
   197     if (map_str == MAP_FAILED) {
   198         close(fd);
   199         return;
   200     }
   201 
   202     input->xkb.keymap = xkb_map_new_from_string(input->display->xkb_context,
   203                                                 map_str,
   204                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
   205                                                 0);
   206     munmap(map_str, size);
   207     close(fd);
   208 
   209     if (!input->xkb.keymap) {
   210         fprintf(stderr, "failed to compile keymap\n");
   211         return;
   212     }
   213 
   214     input->xkb.state = xkb_state_new(input->xkb.keymap);
   215     if (!input->xkb.state) {
   216         fprintf(stderr, "failed to create XKB state\n");
   217         xkb_map_unref(input->xkb.keymap);
   218         input->xkb.keymap = NULL;
   219         return;
   220     }
   221 }
   222 
   223 static void
   224 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
   225                       uint32_t serial, struct wl_surface *surface,
   226                       struct wl_array *keys)
   227 {
   228     struct SDL_WaylandInput *input = data;
   229     SDL_WindowData *window = wl_surface_get_user_data(surface);
   230 
   231     input->keyboard_focus = window;
   232     window->keyboard_device = input;
   233     SDL_SetKeyboardFocus(window->sdlwindow);
   234 }
   235 
   236 static void
   237 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
   238                       uint32_t serial, struct wl_surface *surface)
   239 {
   240     SDL_SetKeyboardFocus(NULL);
   241 }
   242 
   243 static void
   244 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
   245                     uint32_t serial, uint32_t time, uint32_t key,
   246                     uint32_t state_w)
   247 {
   248     struct SDL_WaylandInput *input = data;
   249     SDL_WindowData *window = input->keyboard_focus;
   250     enum wl_keyboard_key_state state = state_w;
   251     const xkb_keysym_t *syms;
   252     uint32_t scancode;
   253     char text[8];
   254     int size;
   255 
   256     if (key < SDL_arraysize(xfree86_scancode_table2)) {
   257         scancode = xfree86_scancode_table2[key];
   258 
   259         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
   260         if (scancode != SDL_SCANCODE_UNKNOWN)
   261             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
   262                                 SDL_PRESSED : SDL_RELEASED, scancode);
   263     }
   264 
   265     if (!window || window->keyboard_device != input || !input->xkb.state)
   266         return;
   267 
   268     // TODO can this happen?
   269     if (xkb_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
   270         return;
   271 
   272     if (state) {
   273         size = xkb_keysym_to_utf8(syms[0], text, sizeof text);
   274 
   275         if (size > 0) {
   276             text[size] = 0;
   277             SDL_SendKeyboardText(text);
   278         }
   279     }
   280 }
   281 
   282 static void
   283 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
   284                           uint32_t serial, uint32_t mods_depressed,
   285                           uint32_t mods_latched, uint32_t mods_locked,
   286                           uint32_t group)
   287 {
   288     struct SDL_WaylandInput *input = data;
   289 
   290     xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
   291                           mods_locked, 0, 0, group);
   292 }
   293 
   294 static const struct wl_keyboard_listener keyboard_listener = {
   295     keyboard_handle_keymap,
   296     keyboard_handle_enter,
   297     keyboard_handle_leave,
   298     keyboard_handle_key,
   299     keyboard_handle_modifiers,
   300 };
   301 
   302 static void
   303 seat_handle_capabilities(void *data, struct wl_seat *seat,
   304                          enum wl_seat_capability caps)
   305 {
   306     struct SDL_WaylandInput *input = data;
   307 
   308     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
   309         input->pointer = wl_seat_get_pointer(seat);
   310         input->display->pointer = input->pointer;
   311         wl_pointer_set_user_data(input->pointer, input);
   312         wl_pointer_add_listener(input->pointer, &pointer_listener,
   313                                 input);
   314     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
   315         wl_pointer_destroy(input->pointer);
   316         input->pointer = NULL;
   317     }
   318 
   319     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
   320         input->keyboard = wl_seat_get_keyboard(seat);
   321         wl_keyboard_set_user_data(input->keyboard, input);
   322         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
   323                                  input);
   324     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
   325         wl_keyboard_destroy(input->keyboard);
   326         input->keyboard = NULL;
   327     }
   328 }
   329 
   330 static const struct wl_seat_listener seat_listener = {
   331     seat_handle_capabilities,
   332 };
   333 
   334 void
   335 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
   336 {
   337     struct SDL_WaylandInput *input;
   338 
   339     input = malloc(sizeof *input);
   340     if (input == NULL)
   341         return;
   342 
   343     memset(input, 0, sizeof *input);
   344     input->display = d;
   345     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
   346 
   347     d->input = input;
   348 
   349     wl_seat_add_listener(input->seat, &seat_listener, input);
   350     wl_seat_set_user_data(input->seat, input);
   351 
   352     wayland_schedule_write(d);
   353 }
   354 
   355 void Wayland_display_destroy_input(SDL_VideoData *d)
   356 {
   357     struct SDL_WaylandInput *input = d->input;
   358 
   359     if (!input)
   360         return;
   361 
   362     if (input->keyboard)
   363         wl_keyboard_destroy(input->keyboard);
   364 
   365     if (input->pointer)
   366         wl_pointer_destroy(input->pointer);
   367 
   368     if (input->seat)
   369         wl_seat_destroy(input->seat);
   370 
   371     if (input->xkb.state)
   372         xkb_state_unref(input->xkb.state);
   373 
   374     if (input->xkb.keymap)
   375         xkb_map_unref(input->xkb.keymap);
   376 
   377     free(input);
   378     d->input = NULL;
   379 }
   380 
   381 /* vi: set ts=4 sw=4 expandtab: */