This commit is contained in:
mengwa113 2025-12-17 04:20:28 +01:00 committed by GitHub
commit c49ff3e47f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 316 additions and 3 deletions

View File

@ -1588,8 +1588,21 @@ void WaylandThread::_wl_seat_on_capabilities(void *data, struct wl_seat *wl_seat
ERR_FAIL_NULL(ss);
// TODO: Handle touch.
// Touch handling.
if (capabilities & WL_SEAT_CAPABILITY_TOUCH) {
if (!ss->wl_touch) {
ss->cursor_surface = wl_compositor_create_surface(ss->registry->wl_compositor);
wl_surface_commit(ss->cursor_surface);
ss->wl_touch = wl_seat_get_touch(wl_seat);
wl_touch_add_listener(ss->wl_touch, &wl_touch_listener, ss);
}
} else {
if (ss->wl_touch) {
wl_touch_destroy(ss->wl_touch);
ss->wl_touch = nullptr;
}
}
// Pointer handling.
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
if (!ss->wl_pointer) {
@ -1713,6 +1726,262 @@ void WaylandThread::_cursor_frame_callback_on_done(void *data, struct wl_callbac
seat_state_update_cursor(ss);
}
void WaylandThread::_wl_touch_on_down(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, struct wl_surface *surface,
int32_t id, wl_fixed_t x, wl_fixed_t y) {
WindowState *ws = wl_surface_get_window_state(surface);
if (!ws) {
return;
}
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
PointerData &pd = ss->pointer_data_buffer;
double scale = window_state_get_scale_factor(ws);
Vector2 position = Vector2(wl_fixed_to_double(x), wl_fixed_to_double(y));
TouchData &bf = ss->touch_data_buffer;
TouchPoint &td = bf.touchs[id];
td.relative = Vector2();
td.position = position;
td.time = time;
td.double_tap = false;
td.canceled = false;
if ((td.time - td.last_time) < 400 && (td.position * scale).distance_to(td.last_position * scale) < 5) {
td.double_tap = true;
}
td.last_position = position;
td.last_time = time;
td.pressed = true;
td.is_activing = true;
bf.touched_id = pd.pointed_id;
bf.last_touched_id = pd.last_pointed_id;
DEBUG_LOG_WAYLAND_THREAD(vformat("Touch down in window %d, id: %d", ws->id, id));
if (wl_touch_get_version(wl_touch) < WL_TOUCH_FRAME_SINCE_VERSION) {
_wl_touch_on_frame(data, wl_touch);
}
}
void WaylandThread::_wl_touch_on_up(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, int32_t id) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
TouchData &bf = ss->touch_data_buffer;
if (!bf.touchs.has(id)) {
return;
}
WaylandThread *wayland_thread = ss->wayland_thread;
ERR_FAIL_NULL(wayland_thread);
WindowState *ws = nullptr;
if (bf.touched_id != DisplayServer::INVALID_WINDOW_ID) {
ws = wayland_thread->window_get_state(bf.touched_id);
ERR_FAIL_NULL(ws);
}
if (ws == nullptr) {
return;
}
TouchPoint &td = bf.touchs[id];
td.relative = Vector2();
td.pressed = false;
td.is_activing = true;
td.time = time;
td.last_time = time;
DEBUG_LOG_WAYLAND_THREAD(vformat("Touch up in window %d, id: %d", ws->id, id));
if (wl_touch_get_version(wl_touch) < WL_TOUCH_FRAME_SINCE_VERSION) {
_wl_touch_on_frame(data, wl_touch);
}
}
void WaylandThread::_wl_touch_on_motion(void *data, struct wl_touch *wl_touch,
uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
TouchData &bf = ss->touch_data_buffer;
if (!bf.touchs.has(id)) {
return;
}
WaylandThread *wayland_thread = ss->wayland_thread;
ERR_FAIL_NULL(wayland_thread);
TouchPoint &td = bf.touchs[id];
Vector2 position = Vector2(wl_fixed_to_double(x_w), wl_fixed_to_double(y_w));
WindowState *ws = nullptr;
if (bf.touched_id != DisplayServer::INVALID_WINDOW_ID) {
ws = wayland_thread->window_get_state(bf.touched_id);
ERR_FAIL_NULL(ws);
}
if (ws == nullptr) {
return;
}
td.position = position;
td.time = time;
td.index = id;
td.pressed = true;
td.is_activing = true;
if (td.time != td.last_time) {
td.relative = Vector2(td.position - td.last_position);
}
td.last_time = time;
td.last_position = position;
DEBUG_LOG_WAYLAND_THREAD(vformat("Touch motion in window %d, id: %d", ws->id, id));
if (wl_touch_get_version(wl_touch) < WL_TOUCH_FRAME_SINCE_VERSION) {
_wl_touch_on_frame(data, wl_touch);
}
}
void WaylandThread::_wl_touch_on_frame(void *data, struct wl_touch *wl_touch) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
WaylandThread *wayland_thread = ss->wayland_thread;
ERR_FAIL_NULL(wayland_thread);
TouchData &bf = ss->touch_data_buffer;
if (bf.touched_id != bf.last_touched_id) {
if (bf.last_touched_id != DisplayServer::INVALID_WINDOW_ID) {
Ref<WindowEventMessage> msg;
msg.instantiate();
msg->id = bf.last_touched_id;
msg->event = DisplayServer::WINDOW_EVENT_MOUSE_EXIT;
wayland_thread->push_message(msg);
}
if (bf.touched_id != DisplayServer::INVALID_WINDOW_ID) {
Ref<WindowEventMessage> msg;
msg.instantiate();
msg->id = bf.touched_id;
msg->event = DisplayServer::WINDOW_EVENT_MOUSE_ENTER;
wayland_thread->push_message(msg);
}
}
WindowState *ws = nullptr;
if (bf.touched_id != DisplayServer::INVALID_WINDOW_ID) {
ws = ss->wayland_thread->window_get_state(bf.touched_id);
ERR_FAIL_NULL(ws);
} else if (bf.last_touched_id != DisplayServer::INVALID_WINDOW_ID) {
ws = ss->wayland_thread->window_get_state(bf.last_touched_id);
ERR_FAIL_NULL(ws);
}
if (ws == nullptr) {
bf.last_touched_id = bf.touched_id;
return;
}
double scale = window_state_get_scale_factor(ws);
for (KeyValue<int32_t, TouchPoint> &pair : bf.touchs) {
TouchPoint &td = pair.value;
if (!td.is_activing) {
continue;
}
td.is_activing = false;
if (td.relative != Vector2()) {
Ref<InputEventScreenDrag> ev;
ev.instantiate();
ev->set_window_id(bf.touched_id);
ev->set_position(td.position * scale);
uint32_t time_delta = td.time - td.last_time;
ev->set_relative(td.relative * scale);
ev->set_relative_screen_position(td.relative);
ev->set_velocity(td.relative * scale / time_delta);
ev->set_screen_velocity(td.relative / time_delta);
ev->set_index(td.index);
Ref<InputEventMessage> msg;
msg.instantiate();
msg->event = ev;
wayland_thread->push_message(msg);
} else {
Ref<InputEventScreenTouch> ev;
ev.instantiate();
ev->set_window_id(bf.touched_id);
ev->set_pressed(td.pressed);
ev->set_position(td.position * scale);
ev->set_index(td.index);
ev->set_double_tap(td.double_tap);
td.double_tap = false;
Ref<InputEventMessage> msg;
msg.instantiate();
msg->event = ev;
wayland_thread->push_message(msg);
}
}
}
void WaylandThread::_wl_touch_on_cancel(void *data, struct wl_touch *wl_touch) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
WaylandThread *wayland_thread = ss->wayland_thread;
ERR_FAIL_NULL(wayland_thread);
TouchData &bf = ss->touch_data_buffer;
for (KeyValue<int32_t, TouchPoint> &pair : bf.touchs) {
TouchPoint &td = pair.value;
if (td.is_activing == true) {
td.canceled = true;
td.is_activing = false;
Ref<InputEventScreenTouch> ev;
ev.instantiate();
ev->set_pressed(false);
ev->set_position(td.position);
ev->set_index(td.index);
ev->set_double_tap(td.double_tap);
ev->set_canceled(td.canceled);
ev->set_window_id(bf.touched_id);
Ref<InputEventMessage> msg;
msg.instantiate();
msg->event = ev;
wayland_thread->push_message(msg);
}
}
}
void WaylandThread::_wl_touch_on_shape(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t major, wl_fixed_t minor) {
}
void WaylandThread::_wl_touch_on_orientation(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t orientation) {
}
void WaylandThread::_wl_pointer_on_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
WindowState *ws = wl_surface_get_window_state(surface);
if (!ws) {
@ -3453,8 +3722,8 @@ void WaylandThread::window_state_update_size(WindowState *p_ws, int p_width, int
bool using_fractional = p_ws->preferred_fractional_scale > 0;
// If neither is true we no-op.
bool scale_changed = false;
bool size_changed = false;
bool scale_changed = true;
bool size_changed = true;
if (p_ws->rect.size.width != p_width || p_ws->rect.size.height != p_height) {
p_ws->rect.size.width = p_width;

View File

@ -353,6 +353,28 @@ public:
CONFINED,
};
struct TouchPoint {
Point2 position;
Point2 last_position;
Vector2 relative;
uint32_t index = 0;
uint32_t time = 0;
uint32_t last_time = 0;
bool pressed = false;
bool canceled = false;
bool double_tap = false;
bool is_activing = false;
};
struct TouchData {
AHashMap<int32_t, TouchPoint> touchs;
DisplayServer::WindowID touched_id = DisplayServer::INVALID_WINDOW_ID;
DisplayServer::WindowID last_touched_id = DisplayServer::INVALID_WINDOW_ID;
};
struct PointerData {
Point2 position;
uint32_t motion_time = 0;
@ -427,6 +449,10 @@ public:
struct wl_seat *wl_seat = nullptr;
uint32_t wl_seat_name = 0;
// Touch.
struct wl_touch *wl_touch = nullptr;
TouchData touch_data_buffer;
// Pointer.
struct wl_pointer *wl_pointer = nullptr;
@ -671,6 +697,14 @@ private:
static void _cursor_frame_callback_on_done(void *data, struct wl_callback *wl_callback, uint32_t time_ms);
static void _wl_touch_on_down(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y);
static void _wl_touch_on_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id);
static void _wl_touch_on_motion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
static void _wl_touch_on_frame(void *data, struct wl_touch *wl_touch);
static void _wl_touch_on_cancel(void *data, struct wl_touch *wl_touch);
static void _wl_touch_on_shape(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t major, wl_fixed_t minor);
static void _wl_touch_on_orientation(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t orientation);
static void _wl_pointer_on_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
static void _wl_pointer_on_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface);
static void _wl_pointer_on_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
@ -821,6 +855,16 @@ private:
.done = _cursor_frame_callback_on_done,
};
static constexpr struct wl_touch_listener wl_touch_listener = {
.down = _wl_touch_on_down,
.up = _wl_touch_on_up,
.motion = _wl_touch_on_motion,
.frame = _wl_touch_on_frame,
.cancel = _wl_touch_on_cancel,
.shape = _wl_touch_on_shape,
.orientation = _wl_touch_on_orientation,
};
static constexpr struct wl_pointer_listener wl_pointer_listener = {
.enter = _wl_pointer_on_enter,
.leave = _wl_pointer_on_leave,