2015-06-21 17:33:46 +02:00
|
|
|
/*
|
|
|
|
Simple DirectMedia Layer
|
2021-01-02 19:25:38 +01:00
|
|
|
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "../../SDL_internal.h"
|
|
|
|
|
|
|
|
#if SDL_VIDEO_DRIVER_WAYLAND
|
|
|
|
|
|
|
|
#include "SDL_stdinc.h"
|
2020-10-06 04:17:52 +02:00
|
|
|
#include "SDL_timer.h"
|
2015-06-21 17:33:46 +02:00
|
|
|
|
2017-08-15 05:22:19 +02:00
|
|
|
#include "../../core/unix/SDL_poll.h"
|
2015-06-21 17:33:46 +02:00
|
|
|
#include "../../events/SDL_sysevents.h"
|
|
|
|
#include "../../events/SDL_events_c.h"
|
|
|
|
#include "../../events/scancodes_xfree86.h"
|
|
|
|
|
|
|
|
#include "SDL_waylandvideo.h"
|
|
|
|
#include "SDL_waylandevents_c.h"
|
|
|
|
#include "SDL_waylandwindow.h"
|
|
|
|
|
|
|
|
#include "SDL_waylanddyn.h"
|
|
|
|
|
2016-09-01 10:26:56 +02:00
|
|
|
#include "pointer-constraints-unstable-v1-client-protocol.h"
|
|
|
|
#include "relative-pointer-unstable-v1-client-protocol.h"
|
2018-06-25 07:42:36 +02:00
|
|
|
#include "xdg-shell-client-protocol.h"
|
2018-02-07 19:13:55 +01:00
|
|
|
#include "xdg-shell-unstable-v6-client-protocol.h"
|
2021-01-20 01:20:07 +01:00
|
|
|
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
2016-09-01 10:26:56 +02:00
|
|
|
|
2020-04-07 19:30:46 +02:00
|
|
|
#ifdef SDL_INPUT_LINUXEV
|
2015-06-21 17:33:46 +02:00
|
|
|
#include <linux/input.h>
|
2020-04-07 19:30:46 +02:00
|
|
|
#else
|
|
|
|
#define BTN_LEFT (0x110)
|
|
|
|
#define BTN_RIGHT (0x111)
|
|
|
|
#define BTN_MIDDLE (0x112)
|
|
|
|
#define BTN_SIDE (0x113)
|
|
|
|
#define BTN_EXTRA (0x114)
|
|
|
|
#endif
|
2015-06-21 17:33:46 +02:00
|
|
|
#include <sys/select.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
|
2021-01-23 02:22:17 +01:00
|
|
|
/* Weston uses a ratio of 10 units per scroll tick */
|
|
|
|
#define WAYLAND_WHEEL_AXIS_UNIT 10
|
|
|
|
|
2017-08-21 20:19:38 +02:00
|
|
|
struct SDL_WaylandTouchPoint {
|
|
|
|
SDL_TouchID id;
|
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
struct wl_surface* surface;
|
|
|
|
|
|
|
|
struct SDL_WaylandTouchPoint* prev;
|
|
|
|
struct SDL_WaylandTouchPoint* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SDL_WaylandTouchPointList {
|
|
|
|
struct SDL_WaylandTouchPoint* head;
|
|
|
|
struct SDL_WaylandTouchPoint* tail;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
|
|
|
|
|
|
|
|
static void
|
|
|
|
touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
|
|
|
|
|
|
|
|
tp->id = id;
|
|
|
|
tp->x = x;
|
|
|
|
tp->y = y;
|
|
|
|
tp->surface = surface;
|
|
|
|
|
|
|
|
if (touch_points.tail) {
|
|
|
|
touch_points.tail->next = tp;
|
|
|
|
tp->prev = touch_points.tail;
|
|
|
|
} else {
|
|
|
|
touch_points.head = tp;
|
|
|
|
tp->prev = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
touch_points.tail = tp;
|
|
|
|
tp->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
touch_update(SDL_TouchID id, float x, float y)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandTouchPoint* tp = touch_points.head;
|
|
|
|
|
|
|
|
while (tp) {
|
|
|
|
if (tp->id == id) {
|
|
|
|
tp->x = x;
|
|
|
|
tp->y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
tp = tp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-08-01 23:22:12 +02:00
|
|
|
touch_del(SDL_TouchID id, float* x, float* y, struct wl_surface **surface)
|
2017-08-21 20:19:38 +02:00
|
|
|
{
|
|
|
|
struct SDL_WaylandTouchPoint* tp = touch_points.head;
|
|
|
|
|
|
|
|
while (tp) {
|
|
|
|
if (tp->id == id) {
|
|
|
|
*x = tp->x;
|
|
|
|
*y = tp->y;
|
2019-08-01 23:22:12 +02:00
|
|
|
*surface = tp->surface;
|
2017-08-21 20:19:38 +02:00
|
|
|
|
|
|
|
if (tp->prev) {
|
|
|
|
tp->prev->next = tp->next;
|
|
|
|
} else {
|
|
|
|
touch_points.head = tp->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tp->next) {
|
|
|
|
tp->next->prev = tp->prev;
|
|
|
|
} else {
|
|
|
|
touch_points.tail = tp->prev;
|
|
|
|
}
|
|
|
|
|
2019-10-30 21:12:36 +01:00
|
|
|
{
|
|
|
|
struct SDL_WaylandTouchPoint *next = tp->next;
|
|
|
|
SDL_free(tp);
|
|
|
|
tp = next;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tp = tp->next;
|
2017-08-21 20:19:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct wl_surface*
|
|
|
|
touch_surface(SDL_TouchID id)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandTouchPoint* tp = touch_points.head;
|
|
|
|
|
|
|
|
while (tp) {
|
|
|
|
if (tp->id == id) {
|
|
|
|
return tp->surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
tp = tp->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
/* Returns the time till next repeat, or 0 if no key is down. */
|
|
|
|
static void
|
|
|
|
keyboard_repeat_handle(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t now)
|
|
|
|
{
|
|
|
|
if (!repeat_info->is_key_down || !repeat_info->is_initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (repeat_info->next_repeat_ms <= now) {
|
|
|
|
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
|
|
|
|
SDL_SendKeyboardKey(SDL_PRESSED, repeat_info->scancode);
|
|
|
|
}
|
|
|
|
if (repeat_info->text[0]) {
|
|
|
|
SDL_SendKeyboardText(repeat_info->text);
|
|
|
|
}
|
|
|
|
repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
keyboard_repeat_clear(SDL_WaylandKeyboardRepeat* repeat_info) {
|
|
|
|
if (!repeat_info->is_initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
repeat_info->is_key_down = SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info,
|
|
|
|
uint32_t scancode, SDL_bool has_text, char text[8]) {
|
|
|
|
if (!repeat_info->is_initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
repeat_info->is_key_down = SDL_TRUE;
|
|
|
|
repeat_info->next_repeat_ms = SDL_GetTicks() + repeat_info->repeat_delay;
|
|
|
|
repeat_info->scancode = scancode;
|
|
|
|
if (has_text) {
|
|
|
|
memcpy(repeat_info->text, text, 8);
|
|
|
|
} else {
|
|
|
|
repeat_info->text[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
void
|
|
|
|
Wayland_PumpEvents(_THIS)
|
|
|
|
{
|
|
|
|
SDL_VideoData *d = _this->driverdata;
|
2020-10-06 04:17:52 +02:00
|
|
|
struct SDL_WaylandInput *input = d->input;
|
Fixed bug 4689 - SDL fails to detect compositor shutdown on Wayland -- program keeps running
M Stoeckl
To reproduce:
1. Run any SDL-based program with a Wayland compositor, orphaning it so that it doesn't have an immediate parent process. (For example, from a terminal, running `supertux2 & disown`.) The program should use the wayland backend, i.e. by setting environment variable SDL_VIDEODRIVER=wayland.
2. Kill the compositor process.
Results:
- The SDL program will keep running.
Expected results:
- The SDL program should close. (What close should mean here, I'm not sure - is injecting an SDL_Quit the appropriate action when a video driver disconnects?)
Build data:
2019-06-22, hg tip (12901:bf8d9d29cbf1), Linux, can reproduce with sway, weston, and other Wayland oompositors.
2019-08-06 08:38:48 +02:00
|
|
|
int err;
|
2015-06-21 17:33:46 +02:00
|
|
|
|
2018-08-23 14:47:38 +02:00
|
|
|
WAYLAND_wl_display_flush(d->display);
|
|
|
|
|
2021-03-29 22:57:03 +02:00
|
|
|
#ifdef SDL_USE_IME
|
|
|
|
if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
|
|
|
|
SDL_IME_PumpEvents();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
if (input) {
|
|
|
|
uint32_t now = SDL_GetTicks();
|
|
|
|
keyboard_repeat_handle(&input->keyboard_repeat, now);
|
|
|
|
}
|
|
|
|
|
2017-08-15 05:22:19 +02:00
|
|
|
if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
|
Fixed bug 4689 - SDL fails to detect compositor shutdown on Wayland -- program keeps running
M Stoeckl
To reproduce:
1. Run any SDL-based program with a Wayland compositor, orphaning it so that it doesn't have an immediate parent process. (For example, from a terminal, running `supertux2 & disown`.) The program should use the wayland backend, i.e. by setting environment variable SDL_VIDEODRIVER=wayland.
2. Kill the compositor process.
Results:
- The SDL program will keep running.
Expected results:
- The SDL program should close. (What close should mean here, I'm not sure - is injecting an SDL_Quit the appropriate action when a video driver disconnects?)
Build data:
2019-06-22, hg tip (12901:bf8d9d29cbf1), Linux, can reproduce with sway, weston, and other Wayland oompositors.
2019-08-06 08:38:48 +02:00
|
|
|
err = WAYLAND_wl_display_dispatch(d->display);
|
|
|
|
} else {
|
|
|
|
err = WAYLAND_wl_display_dispatch_pending(d->display);
|
2017-08-15 05:22:19 +02:00
|
|
|
}
|
Fixed bug 4689 - SDL fails to detect compositor shutdown on Wayland -- program keeps running
M Stoeckl
To reproduce:
1. Run any SDL-based program with a Wayland compositor, orphaning it so that it doesn't have an immediate parent process. (For example, from a terminal, running `supertux2 & disown`.) The program should use the wayland backend, i.e. by setting environment variable SDL_VIDEODRIVER=wayland.
2. Kill the compositor process.
Results:
- The SDL program will keep running.
Expected results:
- The SDL program should close. (What close should mean here, I'm not sure - is injecting an SDL_Quit the appropriate action when a video driver disconnects?)
Build data:
2019-06-22, hg tip (12901:bf8d9d29cbf1), Linux, can reproduce with sway, weston, and other Wayland oompositors.
2019-08-06 08:38:48 +02:00
|
|
|
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();
|
2017-08-15 05:22:19 +02:00
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
2020-05-21 06:06:09 +02:00
|
|
|
static void
|
|
|
|
pointer_handle_motion(void *data, struct wl_pointer *pointer,
|
|
|
|
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
SDL_WindowData *window = input->pointer_focus;
|
|
|
|
input->sx_w = sx_w;
|
|
|
|
input->sy_w = sy_w;
|
|
|
|
if (input->pointer_focus) {
|
|
|
|
const int sx = wl_fixed_to_int(sx_w);
|
|
|
|
const int sy = wl_fixed_to_int(sy_w);
|
|
|
|
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static void
|
|
|
|
pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
|
|
|
wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
SDL_WindowData *window;
|
|
|
|
|
|
|
|
if (!surface) {
|
|
|
|
/* enter event for a window we've just destroyed */
|
|
|
|
return;
|
|
|
|
}
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-15 06:28:04 +02:00
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
/* This handler will be called twice in Wayland 1.4
|
|
|
|
* Once for the window surface which has valid user data
|
|
|
|
* and again for the mouse cursor surface which does not have valid user data
|
|
|
|
* We ignore the later
|
|
|
|
*/
|
|
|
|
|
|
|
|
window = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-15 06:28:04 +02:00
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
if (window) {
|
|
|
|
input->pointer_focus = window;
|
2021-02-26 02:30:47 +01:00
|
|
|
input->pointer_enter_serial = serial;
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SetMouseFocus(window->sdlwindow);
|
2020-05-21 06:06:09 +02:00
|
|
|
/* In the case of e.g. a pointer confine warp, we may receive an enter
|
|
|
|
* event with no following motion event, but with the new coordinates
|
|
|
|
* as part of the enter event. */
|
|
|
|
pointer_handle_motion(data, pointer, serial, sx_w, sy_w);
|
2021-01-21 06:19:24 +01:00
|
|
|
/* If the cursor was changed while our window didn't have pointer
|
|
|
|
* focus, we might need to trigger another call to
|
|
|
|
* wl_pointer_set_cursor() for the new cursor to be displayed. */
|
|
|
|
SDL_SetCursor(NULL);
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|
|
|
uint32_t serial, struct wl_surface *surface)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
|
|
if (input->pointer_focus) {
|
|
|
|
SDL_SetMouseFocus(NULL);
|
|
|
|
input->pointer_focus = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDL_bool
|
|
|
|
ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
|
|
|
|
{
|
|
|
|
SDL_WindowData *window_data = input->pointer_focus;
|
|
|
|
SDL_Window *window = window_data->sdlwindow;
|
|
|
|
|
|
|
|
if (window->hit_test) {
|
|
|
|
const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
|
|
|
|
const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
|
2018-02-07 19:13:55 +01:00
|
|
|
|
|
|
|
static const uint32_t directions_wl[] = {
|
2015-06-21 17:33:46 +02:00
|
|
|
WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
|
|
|
|
WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
|
|
|
|
WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
|
|
|
|
WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
|
|
|
|
};
|
2018-02-07 19:13:55 +01:00
|
|
|
|
|
|
|
/* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs
|
|
|
|
WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */
|
|
|
|
const uint32_t *directions_zxdg = directions_wl;
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
switch (rc) {
|
|
|
|
case SDL_HITTEST_DRAGGABLE:
|
2018-06-25 07:42:36 +02:00
|
|
|
if (input->display->shell.xdg) {
|
|
|
|
xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial);
|
|
|
|
} else if (input->display->shell.zxdg) {
|
2018-02-07 19:13:55 +01:00
|
|
|
zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial);
|
|
|
|
} else {
|
|
|
|
wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial);
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
return SDL_TRUE;
|
|
|
|
|
|
|
|
case SDL_HITTEST_RESIZE_TOPLEFT:
|
|
|
|
case SDL_HITTEST_RESIZE_TOP:
|
|
|
|
case SDL_HITTEST_RESIZE_TOPRIGHT:
|
|
|
|
case SDL_HITTEST_RESIZE_RIGHT:
|
|
|
|
case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
|
|
|
|
case SDL_HITTEST_RESIZE_BOTTOM:
|
|
|
|
case SDL_HITTEST_RESIZE_BOTTOMLEFT:
|
|
|
|
case SDL_HITTEST_RESIZE_LEFT:
|
2018-06-25 07:42:36 +02:00
|
|
|
if (input->display->shell.xdg) {
|
|
|
|
xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
|
|
} else if (input->display->shell.zxdg) {
|
2018-02-07 19:13:55 +01:00
|
|
|
zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
|
|
} else {
|
|
|
|
wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
return SDL_TRUE;
|
|
|
|
|
|
|
|
default: return SDL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-09-01 10:26:56 +02:00
|
|
|
pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
|
|
|
|
uint32_t time, uint32_t button, uint32_t state_w)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
|
|
|
SDL_WindowData *window = input->pointer_focus;
|
|
|
|
enum wl_pointer_button_state state = state_w;
|
|
|
|
uint32_t sdl_button;
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-15 06:28:04 +02:00
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
if (input->pointer_focus) {
|
|
|
|
switch (button) {
|
|
|
|
case BTN_LEFT:
|
|
|
|
sdl_button = SDL_BUTTON_LEFT;
|
2016-09-01 10:26:56 +02:00
|
|
|
if (ProcessHitTest(input, serial)) {
|
2015-06-21 17:33:46 +02:00
|
|
|
return; /* don't pass this event on to app. */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BTN_MIDDLE:
|
|
|
|
sdl_button = SDL_BUTTON_MIDDLE;
|
|
|
|
break;
|
|
|
|
case BTN_RIGHT:
|
|
|
|
sdl_button = SDL_BUTTON_RIGHT;
|
|
|
|
break;
|
|
|
|
case BTN_SIDE:
|
|
|
|
sdl_button = SDL_BUTTON_X1;
|
|
|
|
break;
|
|
|
|
case BTN_EXTRA:
|
|
|
|
sdl_button = SDL_BUTTON_X2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
2020-10-06 04:17:52 +02:00
|
|
|
|
|
|
|
Wayland_data_device_set_serial(input->data_device, serial);
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
SDL_SendMouseButton(window->sdlwindow, 0,
|
|
|
|
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-09-01 10:26:56 +02:00
|
|
|
pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
|
|
|
|
uint32_t time, uint32_t button, uint32_t state_w)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
2016-09-01 10:26:56 +02:00
|
|
|
|
|
|
|
pointer_handle_button_common(input, serial, time, button, state_w);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-03 09:57:12 +01:00
|
|
|
pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
|
|
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
2016-09-01 10:26:56 +02:00
|
|
|
{
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_WindowData *window = input->pointer_focus;
|
|
|
|
enum wl_pointer_axis a = axis;
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-15 06:28:04 +02:00
|
|
|
float x, y;
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
if (input->pointer_focus) {
|
|
|
|
switch (a) {
|
|
|
|
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
|
|
|
x = 0;
|
2018-01-03 19:43:01 +01:00
|
|
|
y = 0 - (float)wl_fixed_to_double(value);
|
2015-06-21 17:33:46 +02:00
|
|
|
break;
|
|
|
|
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
2018-01-03 19:43:01 +01:00
|
|
|
x = 0 - (float)wl_fixed_to_double(value);
|
2015-06-21 17:33:46 +02:00
|
|
|
y = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-23 02:22:17 +01:00
|
|
|
x /= WAYLAND_WHEEL_AXIS_UNIT;
|
|
|
|
y /= WAYLAND_WHEEL_AXIS_UNIT;
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 09:57:12 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-01 10:26:56 +02:00
|
|
|
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;
|
|
|
|
|
2020-04-07 19:30:46 +02:00
|
|
|
if(wl_seat_get_version(input->seat) >= 5)
|
2020-02-03 09:57:12 +01:00
|
|
|
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;
|
2021-01-23 02:22:17 +01:00
|
|
|
float x, y;
|
|
|
|
|
|
|
|
if (input->pointer_curr_axis_info.is_x_discrete)
|
|
|
|
x = input->pointer_curr_axis_info.x;
|
|
|
|
else
|
|
|
|
x = input->pointer_curr_axis_info.x / WAYLAND_WHEEL_AXIS_UNIT;
|
|
|
|
|
|
|
|
if (input->pointer_curr_axis_info.is_y_discrete)
|
|
|
|
y = input->pointer_curr_axis_info.y;
|
|
|
|
else
|
|
|
|
y = input->pointer_curr_axis_info.y / WAYLAND_WHEEL_AXIS_UNIT;
|
2020-02-03 09:57:12 +01:00
|
|
|
|
|
|
|
/* 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));
|
2016-09-01 10:26:56 +02:00
|
|
|
}
|
|
|
|
|
2020-02-03 09:57:12 +01:00
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static const struct wl_pointer_listener pointer_listener = {
|
|
|
|
pointer_handle_enter,
|
|
|
|
pointer_handle_leave,
|
|
|
|
pointer_handle_motion,
|
|
|
|
pointer_handle_button,
|
|
|
|
pointer_handle_axis,
|
2020-02-03 09:57:12 +01:00
|
|
|
pointer_handle_frame, // Version 5
|
|
|
|
pointer_handle_axis_source, // Version 5
|
|
|
|
pointer_handle_axis_stop, // Version 5
|
|
|
|
pointer_handle_axis_discrete, // Version 5
|
2015-06-21 17:33:46 +02:00
|
|
|
};
|
|
|
|
|
2017-08-21 20:19:38 +02:00
|
|
|
static void
|
|
|
|
touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
|
|
|
|
unsigned int timestamp, struct wl_surface *surface,
|
|
|
|
int id, wl_fixed_t fx, wl_fixed_t fy)
|
|
|
|
{
|
2018-12-05 22:49:38 +01:00
|
|
|
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;
|
2017-08-21 20:19:38 +02:00
|
|
|
|
2018-12-05 22:49:38 +01:00
|
|
|
touch_add(id, x, y, surface);
|
2017-08-21 20:19:38 +02:00
|
|
|
|
2019-08-01 23:22:12 +02:00
|
|
|
SDL_SendTouch(1, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f);
|
2017-08-21 20:19:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
|
|
|
|
unsigned int timestamp, int id)
|
|
|
|
{
|
|
|
|
float x = 0, y = 0;
|
2019-08-01 23:22:12 +02:00
|
|
|
struct wl_surface *surface = NULL;
|
|
|
|
SDL_Window *window = NULL;
|
2017-08-21 20:19:38 +02:00
|
|
|
|
2019-08-01 23:22:12 +02:00
|
|
|
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);
|
2017-08-21 20:19:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
|
|
|
|
int id, wl_fixed_t fx, wl_fixed_t fy)
|
|
|
|
{
|
2018-12-05 22:49:38 +01:00
|
|
|
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;
|
|
|
|
|
2017-08-21 20:19:38 +02:00
|
|
|
touch_update(id, x, y);
|
2019-08-01 23:22:12 +02:00
|
|
|
SDL_SendTouchMotion(1, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f);
|
2017-08-21 20:19:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
touch_handler_frame(void *data, struct wl_touch *touch)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
touch_handler_cancel(void *data, struct wl_touch *touch)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_touch_listener touch_listener = {
|
|
|
|
touch_handler_down,
|
|
|
|
touch_handler_up,
|
|
|
|
touch_handler_motion,
|
|
|
|
touch_handler_frame,
|
2017-09-29 19:07:37 +02:00
|
|
|
touch_handler_cancel,
|
|
|
|
NULL, /* shape */
|
|
|
|
NULL, /* orientation */
|
2017-08-21 20:19:38 +02:00
|
|
|
};
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static void
|
|
|
|
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
|
|
uint32_t format, int fd, uint32_t size)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
char *map_str;
|
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
if (map_str == MAP_FAILED) {
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
|
|
|
|
map_str,
|
|
|
|
XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
|
|
0);
|
|
|
|
munmap(map_str, size);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (!input->xkb.keymap) {
|
|
|
|
fprintf(stderr, "failed to compile keymap\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
|
|
|
|
if (!input->xkb.state) {
|
|
|
|
fprintf(stderr, "failed to create XKB state\n");
|
|
|
|
WAYLAND_xkb_keymap_unref(input->xkb.keymap);
|
|
|
|
input->xkb.keymap = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
|
|
|
struct wl_array *keys)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
SDL_WindowData *window;
|
|
|
|
|
|
|
|
if (!surface) {
|
|
|
|
/* enter event for a window we've just destroyed */
|
|
|
|
return;
|
|
|
|
}
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-15 06:28:04 +02:00
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
window = wl_surface_get_user_data(surface);
|
|
|
|
|
|
|
|
if (window) {
|
2016-03-02 20:25:23 +01:00
|
|
|
input->keyboard_focus = window;
|
|
|
|
window->keyboard_device = input;
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SetKeyboardFocus(window->sdlwindow);
|
|
|
|
}
|
2021-03-29 22:57:03 +02:00
|
|
|
#ifdef SDL_USE_IME
|
|
|
|
SDL_IME_SetFocus(SDL_TRUE);
|
|
|
|
#endif
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|
|
|
uint32_t serial, struct wl_surface *surface)
|
|
|
|
{
|
2021-01-25 00:19:48 +01:00
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
|
|
/* Stop key repeat before clearing keyboard focus */
|
|
|
|
keyboard_repeat_clear(&input->keyboard_repeat);
|
|
|
|
|
|
|
|
/* This will release any keys still pressed */
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SetKeyboardFocus(NULL);
|
2021-03-29 22:57:03 +02:00
|
|
|
#ifdef SDL_USE_IME
|
|
|
|
SDL_IME_SetFocus(SDL_FALSE);
|
|
|
|
#endif
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
static SDL_bool
|
2021-03-29 22:57:03 +02:00
|
|
|
keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime)
|
2020-10-06 04:17:52 +02:00
|
|
|
{
|
|
|
|
SDL_WindowData *window = input->keyboard_focus;
|
|
|
|
const xkb_keysym_t *syms;
|
|
|
|
|
|
|
|
if (!window || window->keyboard_device != input || !input->xkb.state) {
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO can this happen?
|
|
|
|
if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
2021-03-29 22:57:03 +02:00
|
|
|
#ifdef SDL_USE_IME
|
|
|
|
if (SDL_IME_ProcessKeyEvent(syms[0], key + 8)) {
|
|
|
|
*handled_by_ime = SDL_TRUE;
|
|
|
|
return SDL_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
return WAYLAND_xkb_keysym_to_utf8(syms[0], text, 8) > 0;
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static void
|
|
|
|
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|
|
|
uint32_t serial, uint32_t time, uint32_t key,
|
|
|
|
uint32_t state_w)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
enum wl_keyboard_key_state state = state_w;
|
2020-10-06 04:17:52 +02:00
|
|
|
uint32_t scancode = SDL_SCANCODE_UNKNOWN;
|
2015-06-21 17:33:46 +02:00
|
|
|
char text[8];
|
2021-03-29 22:57:03 +02:00
|
|
|
SDL_bool has_text = SDL_FALSE;
|
|
|
|
SDL_bool handled_by_ime = SDL_FALSE;
|
|
|
|
|
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
|
|
has_text = keyboard_input_get_text(text, input, key, &handled_by_ime);
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
|
2021-03-29 22:57:03 +02:00
|
|
|
if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) {
|
2015-06-21 17:33:46 +02:00
|
|
|
scancode = xfree86_scancode_table2[key];
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
if (scancode != SDL_SCANCODE_UNKNOWN) {
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
|
|
|
|
SDL_PRESSED : SDL_RELEASED, scancode);
|
2020-10-06 04:17:52 +02:00
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
|
|
if (has_text) {
|
2016-11-06 17:34:27 +01:00
|
|
|
Wayland_data_device_set_serial(input->data_device, serial);
|
2021-03-29 22:57:03 +02:00
|
|
|
if (!handled_by_ime) {
|
|
|
|
SDL_SendKeyboardText(text);
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
2020-10-06 04:17:52 +02:00
|
|
|
keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text);
|
|
|
|
} else {
|
|
|
|
keyboard_repeat_clear(&input->keyboard_repeat);
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
|
|
|
|
uint32_t serial, uint32_t mods_depressed,
|
|
|
|
uint32_t mods_latched, uint32_t mods_locked,
|
|
|
|
uint32_t group)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
|
|
WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
|
|
|
|
mods_locked, 0, 0, group);
|
|
|
|
}
|
|
|
|
|
2020-02-03 09:57:12 +01:00
|
|
|
static void
|
|
|
|
keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
int32_t rate, int32_t delay)
|
|
|
|
{
|
2020-10-06 04:17:52 +02:00
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
input->keyboard_repeat.repeat_rate = SDL_max(0, SDL_min(rate, 1000));
|
|
|
|
input->keyboard_repeat.repeat_delay = delay;
|
|
|
|
input->keyboard_repeat.is_initialized = SDL_TRUE;
|
2020-02-03 09:57:12 +01:00
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static const struct wl_keyboard_listener keyboard_listener = {
|
|
|
|
keyboard_handle_keymap,
|
|
|
|
keyboard_handle_enter,
|
|
|
|
keyboard_handle_leave,
|
|
|
|
keyboard_handle_key,
|
|
|
|
keyboard_handle_modifiers,
|
2020-02-03 09:57:12 +01:00
|
|
|
keyboard_handle_repeat_info, // Version 4
|
2015-06-21 17:33:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
seat_handle_capabilities(void *data, struct wl_seat *seat,
|
|
|
|
enum wl_seat_capability caps)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
|
|
|
|
input->pointer = wl_seat_get_pointer(seat);
|
2020-02-03 09:57:12 +01:00
|
|
|
memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
|
2015-06-21 17:33:46 +02:00
|
|
|
input->display->pointer = input->pointer;
|
|
|
|
wl_pointer_set_user_data(input->pointer, input);
|
|
|
|
wl_pointer_add_listener(input->pointer, &pointer_listener,
|
|
|
|
input);
|
|
|
|
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
|
|
|
|
wl_pointer_destroy(input->pointer);
|
|
|
|
input->pointer = NULL;
|
2018-01-03 19:07:27 +01:00
|
|
|
input->display->pointer = NULL;
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
2017-08-21 20:19:38 +02:00
|
|
|
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
|
2018-11-10 21:15:48 +01:00
|
|
|
SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
|
2017-08-21 20:19:38 +02:00
|
|
|
input->touch = wl_seat_get_touch(seat);
|
|
|
|
wl_touch_set_user_data(input->touch, input);
|
|
|
|
wl_touch_add_listener(input->touch, &touch_listener,
|
|
|
|
input);
|
|
|
|
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
|
|
|
|
SDL_DelTouch(1);
|
|
|
|
wl_touch_destroy(input->touch);
|
|
|
|
input->touch = NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
|
|
|
|
input->keyboard = wl_seat_get_keyboard(seat);
|
|
|
|
wl_keyboard_set_user_data(input->keyboard, input);
|
|
|
|
wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
|
|
|
|
input);
|
|
|
|
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
|
|
|
|
wl_keyboard_destroy(input->keyboard);
|
|
|
|
input->keyboard = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 09:57:12 +01:00
|
|
|
static void
|
|
|
|
seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
|
|
|
{
|
|
|
|
/* unimplemented */
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static const struct wl_seat_listener seat_listener = {
|
|
|
|
seat_handle_capabilities,
|
2020-02-03 09:57:12 +01:00
|
|
|
seat_handle_name, // Version 2
|
2015-06-21 17:33:46 +02:00
|
|
|
};
|
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
static void
|
|
|
|
data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
|
|
|
|
const char *mime_type)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
|
|
|
|
const char *mime_type, int32_t fd)
|
|
|
|
{
|
|
|
|
Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
|
|
|
|
}
|
2020-10-06 04:17:52 +02:00
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
static void
|
|
|
|
data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
|
|
|
|
{
|
|
|
|
Wayland_data_source_destroy(data);
|
|
|
|
}
|
2020-10-06 04:17:52 +02:00
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
static void
|
|
|
|
data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
|
|
|
|
uint32_t dnd_action)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_data_source_listener data_source_listener = {
|
|
|
|
data_source_handle_target,
|
|
|
|
data_source_handle_send,
|
|
|
|
data_source_handle_cancelled,
|
|
|
|
data_source_handle_dnd_drop_performed, // Version 3
|
|
|
|
data_source_handle_dnd_finished, // Version 3
|
|
|
|
data_source_handle_action, // Version 3
|
|
|
|
};
|
|
|
|
|
|
|
|
SDL_WaylandDataSource*
|
|
|
|
Wayland_data_source_create(_THIS)
|
|
|
|
{
|
|
|
|
SDL_WaylandDataSource *data_source = NULL;
|
|
|
|
SDL_VideoData *driver_data = NULL;
|
|
|
|
struct wl_data_source *id = NULL;
|
|
|
|
|
|
|
|
if (_this == NULL || _this->driverdata == NULL) {
|
|
|
|
SDL_SetError("Video driver uninitialized");
|
|
|
|
} else {
|
|
|
|
driver_data = _this->driverdata;
|
|
|
|
|
|
|
|
if (driver_data->data_device_manager != NULL) {
|
|
|
|
id = wl_data_device_manager_create_data_source(
|
|
|
|
driver_data->data_device_manager);
|
|
|
|
}
|
|
|
|
|
2020-10-06 04:17:52 +02:00
|
|
|
if (id == NULL) {
|
2016-11-06 17:34:27 +01:00
|
|
|
SDL_SetError("Wayland unable to create data source");
|
|
|
|
} else {
|
|
|
|
data_source = SDL_calloc(1, sizeof *data_source);
|
|
|
|
if (data_source == NULL) {
|
|
|
|
SDL_OutOfMemory();
|
|
|
|
wl_data_source_destroy(id);
|
|
|
|
} else {
|
|
|
|
WAYLAND_wl_list_init(&(data_source->mimes));
|
|
|
|
data_source->source = id;
|
|
|
|
wl_data_source_set_user_data(id, data_source);
|
|
|
|
wl_data_source_add_listener(id, &data_source_listener,
|
|
|
|
data_source);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return data_source;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
|
|
|
|
const char *mime_type)
|
|
|
|
{
|
|
|
|
SDL_WaylandDataOffer *offer = data;
|
|
|
|
Wayland_data_offer_add_mime(offer, mime_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
|
|
|
|
uint32_t source_actions)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
|
|
|
|
uint32_t dnd_action)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_data_offer_listener data_offer_listener = {
|
|
|
|
data_offer_handle_offer,
|
|
|
|
data_offer_handle_source_actions, // Version 3
|
|
|
|
data_offer_handle_actions, // Version 3
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
|
2018-09-24 20:49:25 +02:00
|
|
|
struct wl_data_offer *id)
|
2016-11-06 17:34:27 +01:00
|
|
|
{
|
|
|
|
SDL_WaylandDataOffer *data_offer = NULL;
|
|
|
|
|
|
|
|
data_offer = SDL_calloc(1, sizeof *data_offer);
|
|
|
|
if (data_offer == NULL) {
|
|
|
|
SDL_OutOfMemory();
|
|
|
|
} else {
|
|
|
|
data_offer->offer = id;
|
|
|
|
data_offer->data_device = data;
|
|
|
|
WAYLAND_wl_list_init(&(data_offer->mimes));
|
|
|
|
wl_data_offer_set_user_data(id, data_offer);
|
|
|
|
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
|
2018-09-24 20:49:25 +02:00
|
|
|
uint32_t serial, struct wl_surface *surface,
|
2016-11-06 17:34:27 +01:00
|
|
|
wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
|
|
|
|
{
|
|
|
|
SDL_WaylandDataDevice *data_device = data;
|
|
|
|
SDL_bool has_mime = SDL_FALSE;
|
2020-10-06 04:17:52 +02:00
|
|
|
uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
data_device->drag_serial = serial;
|
|
|
|
|
|
|
|
if (id != NULL) {
|
|
|
|
data_device->drag_offer = wl_data_offer_get_user_data(id);
|
|
|
|
|
|
|
|
/* TODO: SDL Support more mime types */
|
|
|
|
has_mime = Wayland_data_offer_has_mime(
|
|
|
|
data_device->drag_offer, FILE_MIME);
|
|
|
|
|
|
|
|
/* If drag_mime is NULL this will decline the offer */
|
|
|
|
wl_data_offer_accept(id, serial,
|
|
|
|
(has_mime == SDL_TRUE) ? FILE_MIME : NULL);
|
|
|
|
|
|
|
|
/* SDL only supports "copy" style drag and drop */
|
|
|
|
if (has_mime == SDL_TRUE) {
|
|
|
|
dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
|
|
|
}
|
2019-12-30 08:10:39 +01:00
|
|
|
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);
|
|
|
|
}
|
2016-11-06 17:34:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
|
|
|
|
{
|
|
|
|
SDL_WaylandDataDevice *data_device = data;
|
|
|
|
SDL_WaylandDataOffer *offer = NULL;
|
|
|
|
|
|
|
|
if (data_device->selection_offer != NULL) {
|
|
|
|
data_device->selection_offer = NULL;
|
|
|
|
Wayland_data_offer_destroy(offer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
|
2018-09-24 20:49:25 +02:00
|
|
|
uint32_t time, wl_fixed_t x, wl_fixed_t y)
|
2016-11-06 17:34:27 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
|
|
|
|
{
|
|
|
|
SDL_WaylandDataDevice *data_device = data;
|
|
|
|
void *buffer = NULL;
|
|
|
|
size_t length = 0;
|
|
|
|
|
|
|
|
const char *current_uri = NULL;
|
|
|
|
const char *last_char = NULL;
|
|
|
|
char *current_char = NULL;
|
2020-10-06 04:17:52 +02:00
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
if (data_device->drag_offer != NULL) {
|
|
|
|
/* TODO: SDL Support more mime types */
|
|
|
|
buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
|
|
|
&length, FILE_MIME, SDL_FALSE);
|
|
|
|
|
|
|
|
/* uri-list */
|
|
|
|
current_uri = (const char *)buffer;
|
|
|
|
last_char = (const char *)buffer + length;
|
|
|
|
for (current_char = buffer; current_char < last_char; ++current_char) {
|
|
|
|
if (*current_char == '\n' || *current_char == 0) {
|
|
|
|
if (*current_uri != 0 && *current_uri != '#') {
|
|
|
|
*current_char = 0;
|
|
|
|
SDL_SendDropFile(NULL, current_uri);
|
|
|
|
}
|
|
|
|
current_uri = (const char *)current_char + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
|
2018-09-24 20:49:25 +02:00
|
|
|
struct wl_data_offer *id)
|
2020-10-06 04:17:52 +02:00
|
|
|
{
|
2016-11-06 17:34:27 +01:00
|
|
|
SDL_WaylandDataDevice *data_device = data;
|
|
|
|
SDL_WaylandDataOffer *offer = NULL;
|
|
|
|
|
|
|
|
if (id != NULL) {
|
|
|
|
offer = wl_data_offer_get_user_data(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data_device->selection_offer != offer) {
|
|
|
|
Wayland_data_offer_destroy(data_device->selection_offer);
|
|
|
|
data_device->selection_offer = offer;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_SendClipboardUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_data_device_listener data_device_listener = {
|
|
|
|
data_device_handle_data_offer,
|
|
|
|
data_device_handle_enter,
|
|
|
|
data_device_handle_leave,
|
|
|
|
data_device_handle_motion,
|
|
|
|
data_device_handle_drop,
|
|
|
|
data_device_handle_selection
|
|
|
|
};
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
void
|
2020-04-07 19:30:46 +02:00
|
|
|
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input;
|
2016-11-06 17:34:27 +01:00
|
|
|
SDL_WaylandDataDevice *data_device = NULL;
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
input = SDL_calloc(1, sizeof *input);
|
|
|
|
if (input == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
input->display = d;
|
2020-04-07 19:30:46 +02:00
|
|
|
input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
|
2015-06-21 17:33:46 +02:00
|
|
|
input->sx_w = wl_fixed_from_int(0);
|
|
|
|
input->sy_w = wl_fixed_from_int(0);
|
|
|
|
d->input = input;
|
2020-10-06 04:17:52 +02:00
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
if (d->data_device_manager != NULL) {
|
|
|
|
data_device = SDL_calloc(1, sizeof *data_device);
|
|
|
|
if (data_device == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
data_device->data_device = wl_data_device_manager_get_data_device(
|
|
|
|
d->data_device_manager, input->seat
|
|
|
|
);
|
|
|
|
data_device->video_data = d;
|
|
|
|
|
|
|
|
if (data_device->data_device == NULL) {
|
|
|
|
SDL_free(data_device);
|
|
|
|
} else {
|
|
|
|
wl_data_device_set_user_data(data_device->data_device, data_device);
|
|
|
|
wl_data_device_add_listener(data_device->data_device,
|
|
|
|
&data_device_listener, data_device);
|
|
|
|
input->data_device = data_device;
|
|
|
|
}
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
wl_seat_add_listener(input->seat, &seat_listener, input);
|
|
|
|
wl_seat_set_user_data(input->seat, input);
|
|
|
|
|
|
|
|
WAYLAND_wl_display_flush(d->display);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Wayland_display_destroy_input(SDL_VideoData *d)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = d->input;
|
|
|
|
|
|
|
|
if (!input)
|
|
|
|
return;
|
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
if (input->data_device != NULL) {
|
|
|
|
Wayland_data_device_clear_selection(input->data_device);
|
|
|
|
if (input->data_device->selection_offer != NULL) {
|
|
|
|
Wayland_data_offer_destroy(input->data_device->selection_offer);
|
|
|
|
}
|
|
|
|
if (input->data_device->drag_offer != NULL) {
|
|
|
|
Wayland_data_offer_destroy(input->data_device->drag_offer);
|
|
|
|
}
|
|
|
|
if (input->data_device->data_device != NULL) {
|
|
|
|
wl_data_device_release(input->data_device->data_device);
|
|
|
|
}
|
|
|
|
SDL_free(input->data_device);
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
if (input->keyboard)
|
|
|
|
wl_keyboard_destroy(input->keyboard);
|
|
|
|
|
|
|
|
if (input->pointer)
|
|
|
|
wl_pointer_destroy(input->pointer);
|
|
|
|
|
2017-08-21 20:19:38 +02:00
|
|
|
if (input->touch) {
|
|
|
|
SDL_DelTouch(1);
|
|
|
|
wl_touch_destroy(input->touch);
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
if (input->seat)
|
|
|
|
wl_seat_destroy(input->seat);
|
|
|
|
|
|
|
|
if (input->xkb.state)
|
|
|
|
WAYLAND_xkb_state_unref(input->xkb.state);
|
|
|
|
|
|
|
|
if (input->xkb.keymap)
|
|
|
|
WAYLAND_xkb_keymap_unref(input->xkb.keymap);
|
|
|
|
|
|
|
|
SDL_free(input);
|
|
|
|
d->input = NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-06 17:34:27 +01:00
|
|
|
SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
if (input == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return input->data_device;
|
|
|
|
}
|
|
|
|
|
2018-02-07 19:13:55 +01:00
|
|
|
/* !!! FIXME: just merge these into display_handle_global(). */
|
2016-09-01 10:26:56 +02:00
|
|
|
void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
|
|
|
|
{
|
|
|
|
d->relative_pointer_manager =
|
|
|
|
wl_registry_bind(d->registry, id,
|
|
|
|
&zwp_relative_pointer_manager_v1_interface, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
|
|
|
|
{
|
|
|
|
if (d->relative_pointer_manager)
|
|
|
|
zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
|
|
|
|
{
|
|
|
|
d->pointer_constraints =
|
|
|
|
wl_registry_bind(d->registry, id,
|
|
|
|
&zwp_pointer_constraints_v1_interface, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
|
|
|
|
{
|
|
|
|
if (d->pointer_constraints)
|
|
|
|
zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
relative_pointer_handle_relative_motion(void *data,
|
|
|
|
struct zwp_relative_pointer_v1 *pointer,
|
|
|
|
uint32_t time_hi,
|
|
|
|
uint32_t time_lo,
|
|
|
|
wl_fixed_t dx_w,
|
|
|
|
wl_fixed_t dy_w,
|
|
|
|
wl_fixed_t dx_unaccel_w,
|
|
|
|
wl_fixed_t dy_unaccel_w)
|
|
|
|
{
|
|
|
|
struct SDL_WaylandInput *input = data;
|
|
|
|
SDL_VideoData *d = input->display;
|
|
|
|
SDL_WindowData *window = input->pointer_focus;
|
|
|
|
double dx_unaccel;
|
|
|
|
double dy_unaccel;
|
|
|
|
double dx;
|
|
|
|
double dy;
|
|
|
|
|
|
|
|
dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
|
|
|
|
dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
|
|
|
|
|
|
|
|
/* Add left over fraction from last event. */
|
|
|
|
dx_unaccel += input->dx_frac;
|
|
|
|
dy_unaccel += input->dy_frac;
|
|
|
|
|
|
|
|
input->dx_frac = modf(dx_unaccel, &dx);
|
|
|
|
input->dy_frac = modf(dy_unaccel, &dy);
|
|
|
|
|
|
|
|
if (input->pointer_focus && d->relative_mouse_mode) {
|
|
|
|
SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
|
|
|
|
relative_pointer_handle_relative_motion,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
locked_pointer_locked(void *data,
|
|
|
|
struct zwp_locked_pointer_v1 *locked_pointer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
locked_pointer_unlocked(void *data,
|
|
|
|
struct zwp_locked_pointer_v1 *locked_pointer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
|
|
|
|
locked_pointer_locked,
|
|
|
|
locked_pointer_unlocked,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
lock_pointer_to_window(SDL_Window *window,
|
|
|
|
struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
SDL_WindowData *w = window->driverdata;
|
|
|
|
SDL_VideoData *d = input->display;
|
|
|
|
struct zwp_locked_pointer_v1 *locked_pointer;
|
|
|
|
|
|
|
|
if (w->locked_pointer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
locked_pointer =
|
|
|
|
zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
|
|
|
|
w->surface,
|
|
|
|
input->pointer,
|
|
|
|
NULL,
|
|
|
|
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
|
|
|
zwp_locked_pointer_v1_add_listener(locked_pointer,
|
|
|
|
&locked_pointer_listener,
|
|
|
|
window);
|
|
|
|
|
|
|
|
w->locked_pointer = locked_pointer;
|
|
|
|
}
|
|
|
|
|
2020-07-21 19:14:24 +02:00
|
|
|
static void pointer_confine_destroy(struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
if (input->confined_pointer) {
|
|
|
|
zwp_confined_pointer_v1_destroy(input->confined_pointer);
|
|
|
|
input->confined_pointer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-01 10:26:56 +02:00
|
|
|
int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
SDL_VideoDevice *vd = SDL_GetVideoDevice();
|
|
|
|
SDL_VideoData *d = input->display;
|
|
|
|
SDL_Window *window;
|
|
|
|
struct zwp_relative_pointer_v1 *relative_pointer;
|
|
|
|
|
|
|
|
if (!d->relative_pointer_manager)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!d->pointer_constraints)
|
|
|
|
return -1;
|
|
|
|
|
2018-12-06 16:39:33 +01:00
|
|
|
if (!input->pointer)
|
|
|
|
return -1;
|
|
|
|
|
2020-07-21 19:14:24 +02:00
|
|
|
/* If we have a pointer confine active, we must destroy it here because
|
|
|
|
* creating a locked pointer otherwise would be a protocol error. */
|
|
|
|
pointer_confine_destroy(input);
|
|
|
|
|
2016-09-01 10:26:56 +02:00
|
|
|
if (!input->relative_pointer) {
|
|
|
|
relative_pointer =
|
|
|
|
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
|
|
|
d->relative_pointer_manager,
|
|
|
|
input->pointer);
|
|
|
|
zwp_relative_pointer_v1_add_listener(relative_pointer,
|
|
|
|
&relative_pointer_listener,
|
|
|
|
input);
|
|
|
|
input->relative_pointer = relative_pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (window = vd->windows; window; window = window->next)
|
|
|
|
lock_pointer_to_window(window, input);
|
|
|
|
|
|
|
|
d->relative_mouse_mode = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
SDL_VideoDevice *vd = SDL_GetVideoDevice();
|
|
|
|
SDL_VideoData *d = input->display;
|
|
|
|
SDL_Window *window;
|
|
|
|
SDL_WindowData *w;
|
|
|
|
|
|
|
|
for (window = vd->windows; window; window = window->next) {
|
|
|
|
w = window->driverdata;
|
|
|
|
if (w->locked_pointer)
|
|
|
|
zwp_locked_pointer_v1_destroy(w->locked_pointer);
|
|
|
|
w->locked_pointer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
zwp_relative_pointer_v1_destroy(input->relative_pointer);
|
|
|
|
input->relative_pointer = NULL;
|
|
|
|
|
|
|
|
d->relative_mouse_mode = 0;
|
|
|
|
|
2020-07-21 19:14:24 +02:00
|
|
|
if (input->confined_pointer_window)
|
|
|
|
Wayland_input_confine_pointer(input->confined_pointer_window, input);
|
|
|
|
|
2016-09-01 10:26:56 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-17 19:55:44 +02:00
|
|
|
static void
|
|
|
|
confined_pointer_confined(void *data,
|
|
|
|
struct zwp_confined_pointer_v1 *confined_pointer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
confined_pointer_unconfined(void *data,
|
|
|
|
struct zwp_confined_pointer_v1 *confined_pointer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
|
|
|
|
confined_pointer_confined,
|
|
|
|
confined_pointer_unconfined,
|
|
|
|
};
|
|
|
|
|
|
|
|
int Wayland_input_confine_pointer(SDL_Window *window, struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
SDL_WindowData *w = window->driverdata;
|
|
|
|
SDL_VideoData *d = input->display;
|
|
|
|
struct zwp_confined_pointer_v1 *confined_pointer;
|
|
|
|
|
|
|
|
if (!d->pointer_constraints)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!input->pointer)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* A confine may already be active, in which case we should destroy it and
|
|
|
|
* create a new one. */
|
|
|
|
if (input->confined_pointer)
|
|
|
|
Wayland_input_unconfine_pointer(input);
|
|
|
|
|
2020-07-21 19:14:24 +02:00
|
|
|
input->confined_pointer_window = window;
|
|
|
|
|
|
|
|
/* We cannot create a confine if the pointer is already locked. Defer until
|
|
|
|
* the pointer is unlocked. */
|
|
|
|
if (d->relative_mouse_mode)
|
|
|
|
return 0;
|
|
|
|
|
2020-04-17 19:55:44 +02:00
|
|
|
confined_pointer =
|
|
|
|
zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
|
|
|
|
w->surface,
|
|
|
|
input->pointer,
|
|
|
|
NULL,
|
|
|
|
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
|
|
|
zwp_confined_pointer_v1_add_listener(confined_pointer,
|
|
|
|
&confined_pointer_listener,
|
|
|
|
window);
|
|
|
|
|
|
|
|
input->confined_pointer = confined_pointer;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input)
|
|
|
|
{
|
2020-07-21 19:14:24 +02:00
|
|
|
pointer_confine_destroy(input);
|
|
|
|
input->confined_pointer_window = NULL;
|
2020-04-17 19:55:44 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:20:07 +01:00
|
|
|
int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input)
|
|
|
|
{
|
|
|
|
SDL_WindowData *w = window->driverdata;
|
|
|
|
SDL_VideoData *d = input->display;
|
|
|
|
|
|
|
|
if (!d->key_inhibitor_manager)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (w->key_inhibitor)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
w->key_inhibitor =
|
|
|
|
zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(d->key_inhibitor_manager,
|
|
|
|
w->surface,
|
|
|
|
input->seat);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Wayland_input_ungrab_keyboard(SDL_Window *window)
|
|
|
|
{
|
|
|
|
SDL_WindowData *w = window->driverdata;
|
|
|
|
|
|
|
|
if (w->key_inhibitor) {
|
|
|
|
zwp_keyboard_shortcuts_inhibitor_v1_destroy(w->key_inhibitor);
|
|
|
|
w->key_inhibitor = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
|
|
|
|
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|