| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | struct xkb_keymap *keymap; |
| | | struct xkb_state *state; |
| | | } xkb; |
| | | |
| | | /* information about axis events on current frame */ |
| | | struct { |
| | | SDL_bool is_x_discrete; |
| | | float x; |
| | | |
| | | SDL_bool is_y_discrete; |
| | | float y; |
| | | } pointer_curr_axis_info; |
| | | }; |
| | | |
| | | struct SDL_WaylandTouchPoint { |
| | |
| | | } |
| | | |
| | | static void |
| | | touch_del(SDL_TouchID id, float* x, float* y) |
| | | touch_del(SDL_TouchID id, float* x, float* y, struct wl_surface **surface) |
| | | { |
| | | struct SDL_WaylandTouchPoint* tp = touch_points.head; |
| | | |
| | |
| | | if (tp->id == id) { |
| | | *x = tp->x; |
| | | *y = tp->y; |
| | | *surface = tp->surface; |
| | | |
| | | if (tp->prev) { |
| | | tp->prev->next = tp->next; |
| | |
| | | touch_points.tail = tp->prev; |
| | | } |
| | | |
| | | SDL_free(tp); |
| | | { |
| | | struct SDL_WaylandTouchPoint *next = tp->next; |
| | | SDL_free(tp); |
| | | tp = next; |
| | | } |
| | | } else { |
| | | tp = tp->next; |
| | | } |
| | | |
| | | tp = tp->next; |
| | | } |
| | | } |
| | | |
| | |
| | | Wayland_PumpEvents(_THIS) |
| | | { |
| | | SDL_VideoData *d = _this->driverdata; |
| | | int err; |
| | | |
| | | WAYLAND_wl_display_flush(d->display); |
| | | |
| | | if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) { |
| | | WAYLAND_wl_display_dispatch(d->display); |
| | | err = WAYLAND_wl_display_dispatch(d->display); |
| | | } else { |
| | | err = WAYLAND_wl_display_dispatch_pending(d->display); |
| | | } |
| | | else |
| | | { |
| | | WAYLAND_wl_display_dispatch_pending(d->display); |
| | | if (err == -1 && !d->display_disconnected) { |
| | | /* Something has failed with the Wayland connection -- for example, |
| | | * the compositor may have shut down and closed its end of the socket, |
| | | * or there is a library-specific error. No recovery is possible. */ |
| | | d->display_disconnected = 1; |
| | | /* Only send a single quit message, as application shutdown might call |
| | | * SDL_PumpEvents */ |
| | | SDL_SendQuit(); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_axis_common(struct SDL_WaylandInput *input, |
| | | uint32_t time, uint32_t axis, wl_fixed_t value) |
| | | pointer_handle_axis_common_v1(struct SDL_WaylandInput *input, |
| | | uint32_t time, uint32_t axis, wl_fixed_t value) |
| | | { |
| | | SDL_WindowData *window = input->pointer_focus; |
| | | enum wl_pointer_axis a = axis; |
| | |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_axis_common(struct SDL_WaylandInput *input, SDL_bool discrete, |
| | | uint32_t axis, wl_fixed_t value) |
| | | { |
| | | enum wl_pointer_axis a = axis; |
| | | |
| | | if (input->pointer_focus) { |
| | | switch (a) { |
| | | case WL_POINTER_AXIS_VERTICAL_SCROLL: |
| | | if (discrete) { |
| | | /* this is a discrete axis event so we process it and flag |
| | | * to ignore future continuous axis events in this frame */ |
| | | input->pointer_curr_axis_info.is_y_discrete = SDL_TRUE; |
| | | } else if(input->pointer_curr_axis_info.is_y_discrete) { |
| | | /* this is a continuous axis event and we have already |
| | | * processed a discrete axis event before so we ignore it */ |
| | | break; |
| | | } |
| | | input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value); |
| | | break; |
| | | case WL_POINTER_AXIS_HORIZONTAL_SCROLL: |
| | | if (discrete) { |
| | | /* this is a discrete axis event so we process it and flag |
| | | * to ignore future continuous axis events in this frame */ |
| | | input->pointer_curr_axis_info.is_x_discrete = SDL_TRUE; |
| | | } else if(input->pointer_curr_axis_info.is_x_discrete) { |
| | | /* this is a continuous axis event and we have already |
| | | * processed a discrete axis event before so we ignore it */ |
| | | break; |
| | | } |
| | | input->pointer_curr_axis_info.x = 0 - (float)wl_fixed_to_double(value); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_axis(void *data, struct wl_pointer *pointer, |
| | | uint32_t time, uint32_t axis, wl_fixed_t value) |
| | | { |
| | | struct SDL_WaylandInput *input = data; |
| | | |
| | | pointer_handle_axis_common(input, time, axis, value); |
| | | if(wl_seat_interface.version >= 5) |
| | | pointer_handle_axis_common(input, SDL_FALSE, axis, value); |
| | | else |
| | | pointer_handle_axis_common_v1(input, time, axis, value); |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_frame(void *data, struct wl_pointer *pointer) |
| | | { |
| | | struct SDL_WaylandInput *input = data; |
| | | SDL_WindowData *window = input->pointer_focus; |
| | | float x = input->pointer_curr_axis_info.x, y = input->pointer_curr_axis_info.y; |
| | | |
| | | /* clear pointer_curr_axis_info for next frame */ |
| | | memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info); |
| | | |
| | | if(x == 0.0f && y == 0.0f) |
| | | return; |
| | | else |
| | | SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_axis_source(void *data, struct wl_pointer *pointer, |
| | | uint32_t axis_source) |
| | | { |
| | | /* unimplemented */ |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_axis_stop(void *data, struct wl_pointer *pointer, |
| | | uint32_t time, uint32_t axis) |
| | | { |
| | | /* unimplemented */ |
| | | } |
| | | |
| | | static void |
| | | pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer, |
| | | uint32_t axis, int32_t discrete) |
| | | { |
| | | struct SDL_WaylandInput *input = data; |
| | | |
| | | pointer_handle_axis_common(input, SDL_TRUE, axis, wl_fixed_from_int(discrete)); |
| | | } |
| | | |
| | | |
| | | static const struct wl_pointer_listener pointer_listener = { |
| | | pointer_handle_enter, |
| | |
| | | pointer_handle_motion, |
| | | pointer_handle_button, |
| | | pointer_handle_axis, |
| | | NULL, /* frame */ |
| | | NULL, /* axis_source */ |
| | | NULL, /* axis_stop */ |
| | | NULL, /* axis_discrete */ |
| | | pointer_handle_frame, // Version 5 |
| | | pointer_handle_axis_source, // Version 5 |
| | | pointer_handle_axis_stop, // Version 5 |
| | | pointer_handle_axis_discrete, // Version 5 |
| | | }; |
| | | |
| | | static void |
| | |
| | | unsigned int timestamp, struct wl_surface *surface, |
| | | int id, wl_fixed_t fx, wl_fixed_t fy) |
| | | { |
| | | float x, y; |
| | | SDL_WindowData* window; |
| | | |
| | | window = (SDL_WindowData *)wl_surface_get_user_data(surface); |
| | | |
| | | x = wl_fixed_to_double(fx) / window->sdlwindow->w; |
| | | y = wl_fixed_to_double(fy) / window->sdlwindow->h; |
| | | SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); |
| | | const double dblx = wl_fixed_to_double(fx); |
| | | const double dbly = wl_fixed_to_double(fy); |
| | | const float x = dblx / window_data->sdlwindow->w; |
| | | const float y = dbly / window_data->sdlwindow->h; |
| | | |
| | | touch_add(id, x, y, surface); |
| | | SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f); |
| | | |
| | | SDL_SendTouch(1, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f); |
| | | } |
| | | |
| | | static void |
| | |
| | | unsigned int timestamp, int id) |
| | | { |
| | | float x = 0, y = 0; |
| | | struct wl_surface *surface = NULL; |
| | | SDL_Window *window = NULL; |
| | | |
| | | touch_del(id, &x, &y); |
| | | SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f); |
| | | touch_del(id, &x, &y, &surface); |
| | | |
| | | if (surface) { |
| | | SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); |
| | | window = window_data->sdlwindow; |
| | | } |
| | | |
| | | SDL_SendTouch(1, (SDL_FingerID)id, window, SDL_FALSE, x, y, 0.0f); |
| | | } |
| | | |
| | | static void |
| | | touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp, |
| | | int id, wl_fixed_t fx, wl_fixed_t fy) |
| | | { |
| | | float x, y; |
| | | SDL_WindowData* window; |
| | | |
| | | window = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); |
| | | |
| | | x = wl_fixed_to_double(fx) / window->sdlwindow->w; |
| | | y = wl_fixed_to_double(fy) / window->sdlwindow->h; |
| | | SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); |
| | | const double dblx = wl_fixed_to_double(fx); |
| | | const double dbly = wl_fixed_to_double(fy); |
| | | const float x = dblx / window_data->sdlwindow->w; |
| | | const float y = dbly / window_data->sdlwindow->h; |
| | | |
| | | touch_update(id, x, y); |
| | | SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f); |
| | | SDL_SendTouchMotion(1, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f); |
| | | } |
| | | |
| | | static void |
| | |
| | | mods_locked, 0, 0, group); |
| | | } |
| | | |
| | | static void |
| | | keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, |
| | | int32_t rate, int32_t delay) |
| | | { |
| | | /* unimplemented */ |
| | | } |
| | | |
| | | static const struct wl_keyboard_listener keyboard_listener = { |
| | | keyboard_handle_keymap, |
| | | keyboard_handle_enter, |
| | | keyboard_handle_leave, |
| | | keyboard_handle_key, |
| | | keyboard_handle_modifiers, |
| | | NULL, /* repeat_info */ |
| | | keyboard_handle_repeat_info, // Version 4 |
| | | }; |
| | | |
| | | static void |
| | |
| | | |
| | | if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { |
| | | input->pointer = wl_seat_get_pointer(seat); |
| | | memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info); |
| | | input->display->pointer = input->pointer; |
| | | wl_pointer_set_user_data(input->pointer, input); |
| | | wl_pointer_add_listener(input->pointer, &pointer_listener, |
| | |
| | | } |
| | | |
| | | if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { |
| | | SDL_AddTouch(1, "wayland_touch"); |
| | | SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch"); |
| | | input->touch = wl_seat_get_touch(seat); |
| | | wl_touch_set_user_data(input->touch, input); |
| | | wl_touch_add_listener(input->touch, &touch_listener, |
| | |
| | | } |
| | | } |
| | | |
| | | static void |
| | | seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) |
| | | { |
| | | /* unimplemented */ |
| | | } |
| | | |
| | | static const struct wl_seat_listener seat_listener = { |
| | | seat_handle_capabilities, |
| | | NULL, /* name */ |
| | | seat_handle_name, // Version 2 |
| | | }; |
| | | |
| | | static void |
| | |
| | | if (has_mime == SDL_TRUE) { |
| | | dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; |
| | | } |
| | | wl_data_offer_set_actions(data_device->drag_offer->offer, |
| | | dnd_action, dnd_action); |
| | | if (wl_data_offer_get_version(data_device->drag_offer->offer) >= 3) { |
| | | wl_data_offer_set_actions(data_device->drag_offer->offer, |
| | | dnd_action, dnd_action); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | return; |
| | | |
| | | input->display = d; |
| | | input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1); |
| | | if (wl_seat_interface.version >= 5) |
| | | input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 5); |
| | | else |
| | | input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1); |
| | | input->sx_w = wl_fixed_from_int(0); |
| | | input->sy_w = wl_fixed_from_int(0); |
| | | d->input = input; |
| | |
| | | if (!d->pointer_constraints) |
| | | return -1; |
| | | |
| | | if (!input->pointer) |
| | | return -1; |
| | | |
| | | if (!input->relative_pointer) { |
| | | relative_pointer = |
| | | zwp_relative_pointer_manager_v1_get_relative_pointer( |