mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-13 14:32:57 -04:00
backend/wayland: implement multi-output touch
The wayland backend mapped every touch event to the first output and carried a TODO asking for multi-output support. Track the output each touch point belongs to: on touch down, resolve it from the event's wl_surface (falling back to the first output), store it per touch id, and convert coordinates against that output for down and motion events. This makes touch work correctly when the backend drives multiple outputs. Closes #4102
This commit is contained in:
parent
fc1cc7656a
commit
a6b3d52f5d
2 changed files with 60 additions and 21 deletions
|
|
@ -110,23 +110,48 @@ void init_seat_keyboard(struct wlr_wl_seat *seat) {
|
|||
&seat->wlr_keyboard.base);
|
||||
}
|
||||
|
||||
static void touch_coordinates_to_absolute(struct wlr_wl_seat *seat,
|
||||
static struct wlr_wl_output *first_wl_output(struct wlr_wl_seat *seat) {
|
||||
struct wlr_wl_output *output;
|
||||
wl_list_for_each(output, &seat->backend->outputs, link) {
|
||||
return output;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wlr_wl_output *touch_output_for_id(struct wlr_wl_seat *seat,
|
||||
int32_t id) {
|
||||
struct wlr_wl_touch_points *points = &seat->touch_points;
|
||||
for (size_t i = 0; i < points->len; i++) {
|
||||
if (points->ids[i] == id) {
|
||||
return points->outputs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void touch_set_output(struct wlr_wl_seat *seat,
|
||||
struct wlr_wl_output *output) {
|
||||
if (output == NULL) {
|
||||
return;
|
||||
}
|
||||
const char *name = output->wlr_output.name;
|
||||
if (seat->wlr_touch.output_name != NULL &&
|
||||
strcmp(seat->wlr_touch.output_name, name) == 0) {
|
||||
return;
|
||||
}
|
||||
free(seat->wlr_touch.output_name);
|
||||
seat->wlr_touch.output_name = strdup(name);
|
||||
}
|
||||
|
||||
static void touch_coordinates_to_absolute(struct wlr_wl_output *output,
|
||||
wl_fixed_t x, wl_fixed_t y, double *sx, double *sy) {
|
||||
/**
|
||||
* TODO: multi-output touch support
|
||||
* Although the wayland backend supports multi-output pointers, the support
|
||||
* for multi-output touch has been left on the side for simplicity reasons.
|
||||
* If this is a feature you want/need, please open an issue on the wlroots
|
||||
* tracker here https://gitlab.freedesktop.org/wlroots/wlroots/-/issues
|
||||
*/
|
||||
struct wlr_wl_output *output, *tmp;
|
||||
wl_list_for_each_safe(output, tmp, &seat->backend->outputs, link) {
|
||||
if (output == NULL || output->wlr_output.width <= 0 ||
|
||||
output->wlr_output.height <= 0) {
|
||||
*sx = *sy = 0;
|
||||
return;
|
||||
}
|
||||
*sx = wl_fixed_to_double(x) / output->wlr_output.width;
|
||||
*sy = wl_fixed_to_double(y) / output->wlr_output.height;
|
||||
return; // Choose the first output in the list
|
||||
}
|
||||
|
||||
*sx = *sy = 0;
|
||||
}
|
||||
|
||||
static void touch_handle_down(void *data, struct wl_touch *wl_touch,
|
||||
|
|
@ -135,16 +160,25 @@ static void touch_handle_down(void *data, struct wl_touch *wl_touch,
|
|||
struct wlr_wl_seat *seat = data;
|
||||
struct wlr_touch *touch = &seat->wlr_touch;
|
||||
|
||||
struct wlr_wl_output *output = surface != NULL ?
|
||||
get_wl_output_from_surface(seat->backend, surface) : NULL;
|
||||
if (output == NULL) {
|
||||
output = first_wl_output(seat);
|
||||
}
|
||||
|
||||
struct wlr_wl_touch_points *points = &seat->touch_points;
|
||||
assert(points->len != sizeof(points->ids) / sizeof(points->ids[0]));
|
||||
points->outputs[points->len] = output;
|
||||
points->ids[points->len++] = id;
|
||||
|
||||
touch_set_output(seat, output);
|
||||
|
||||
struct wlr_touch_down_event event = {
|
||||
.touch = touch,
|
||||
.time_msec = time,
|
||||
.touch_id = id,
|
||||
};
|
||||
touch_coordinates_to_absolute(seat, x, y, &event.x, &event.y);
|
||||
touch_coordinates_to_absolute(output, x, y, &event.x, &event.y);
|
||||
wl_signal_emit_mutable(&touch->events.down, &event);
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +188,8 @@ static bool remove_touch_point(struct wlr_wl_touch_points *points, int32_t id) {
|
|||
if (points->ids[i] == id) {
|
||||
size_t remaining = points->len - i - 1;
|
||||
memmove(&points->ids[i], &points->ids[i + 1], remaining * sizeof(id));
|
||||
memmove(&points->outputs[i], &points->outputs[i + 1],
|
||||
remaining * sizeof(points->outputs[0]));
|
||||
points->len--;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -181,13 +217,16 @@ static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
|
|||
struct wlr_wl_seat *seat = data;
|
||||
struct wlr_touch *touch = &seat->wlr_touch;
|
||||
|
||||
struct wlr_wl_output *output = touch_output_for_id(seat, id);
|
||||
touch_set_output(seat, output);
|
||||
|
||||
struct wlr_touch_motion_event event = {
|
||||
.touch = touch,
|
||||
.time_msec = time,
|
||||
.touch_id = id,
|
||||
};
|
||||
|
||||
touch_coordinates_to_absolute(seat, x, y, &event.x, &event.y);
|
||||
touch_coordinates_to_absolute(output, x, y, &event.x, &event.y);
|
||||
wl_signal_emit_mutable(&touch->events.motion, &event);
|
||||
}
|
||||
|
||||
|
|
@ -244,11 +283,10 @@ void init_seat_touch(struct wlr_wl_seat *seat) {
|
|||
|
||||
wlr_touch_init(&seat->wlr_touch, &touch_impl, name);
|
||||
|
||||
struct wlr_wl_output *output;
|
||||
wl_list_for_each(output, &seat->backend->outputs, link) {
|
||||
/* Multi-output touch not supported */
|
||||
struct wlr_wl_output *output = first_wl_output(seat);
|
||||
if (output != NULL) {
|
||||
/* Default until the first touch point lands on a known output */
|
||||
seat->wlr_touch.output_name = strdup(output->wlr_output.name);
|
||||
break;
|
||||
}
|
||||
|
||||
wl_touch_add_listener(seat->wl_touch, &touch_listener, seat);
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ struct wlr_wl_pointer {
|
|||
|
||||
struct wlr_wl_touch_points {
|
||||
int32_t ids[64];
|
||||
struct wlr_wl_output *outputs[64];
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue