diff options
author | Michael Olbrich <m.olbrich@pengutronix.de> | 2021-01-20 09:26:01 +0100 |
---|---|---|
committer | Daniel Stone <daniels@collabora.com> | 2023-03-31 12:10:26 +0000 |
commit | 818c1c275cc8a2275fc80f52dd0493a35703cb02 (patch) | |
tree | bd8ff3b65624bdec4c45e2405186b5163ee9003b | |
parent | ce99b181a33e14a816ccd1a77e26f554bba50988 (diff) | |
download | weston-818c1c275cc8a2275fc80f52dd0493a35703cb02.tar.gz |
libweston: handle tablet cursors in the compositor
The tablet is given a separate cursor. Most tablet interaction is an absolute
interaction and shouldn't need a cursor at all, but usually the cursor is used
to indicate the type of virtual tool currently assigned.
Based on patches from
Peter Hutterer <peter.hutterer@who-t.net>
Lyude Paul <thatslyude@gmail.com>
Bastian Farkas <bfarkas@de.adit-jv.com>
Maniraj Devadoss <Maniraj.Devadoss@in.bosch.com>
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
-rw-r--r-- | include/libweston/libweston.h | 10 | ||||
-rw-r--r-- | libweston/compositor.c | 6 | ||||
-rw-r--r-- | libweston/input.c | 128 |
3 files changed, 144 insertions, 0 deletions
diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index b18d0639..207cf771 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -908,6 +908,12 @@ struct weston_tablet_tool { bool tip_is_down; struct timespec frame_time; + + struct weston_view *sprite; + struct weston_coord_surface hotspot; + struct wl_listener sprite_destroy_listener; + + struct weston_coord_global pos; }; struct weston_tablet { @@ -1064,6 +1070,10 @@ void weston_tablet_tool_send_frame(struct weston_tablet_tool *tool, const struct timespec *time); +void +weston_tablet_tool_cursor_move(struct weston_tablet_tool *tool, + struct weston_coord_global pos); + void weston_seat_set_selection(struct weston_seat *seat, diff --git a/libweston/compositor.c b/libweston/compositor.c index 82363d29..ef6d7872 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -2063,6 +2063,7 @@ weston_view_unmap(struct weston_view *view) struct weston_pointer *pointer = weston_seat_get_pointer(seat); struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat); + struct weston_tablet_tool *tool; if (keyboard && keyboard->focus == view->surface) weston_keyboard_set_focus(keyboard, NULL); @@ -2070,6 +2071,11 @@ weston_view_unmap(struct weston_view *view) weston_pointer_clear_focus(pointer); if (touch && touch->focus == view) weston_touch_set_focus(touch, NULL); + + wl_list_for_each(tool, &seat->tablet_tool_list, link) { + if (tool->focus == view) + weston_tablet_tool_set_focus(tool, NULL, 0); + } } } weston_signal_emit_mutable(&view->unmap_signal, view); diff --git a/libweston/input.c b/libweston/input.c index 4301a288..4f3c7ec1 100644 --- a/libweston/input.c +++ b/libweston/input.c @@ -1563,6 +1563,10 @@ weston_tablet_tool_send_proximity_out(struct weston_tablet_tool *tool, const struct timespec *time) { weston_tablet_tool_set_focus(tool, NULL, time); + + /* Hide the cursor */ + if (tool->sprite && weston_surface_is_mapped(tool->sprite->surface)) + weston_surface_unmap(tool->sprite->surface); } static void @@ -1584,6 +1588,7 @@ weston_tablet_tool_send_motion(struct weston_tablet_tool *tool, current_view = weston_compositor_pick_view(tool->seat->compositor, pos); if (current_view != tool->focus) weston_tablet_tool_set_focus(tool, current_view, time); + weston_tablet_tool_cursor_move(tool, pos); surf_pos = weston_coord_global_to_surface(tool->focus, pos); wl_resource_for_each(resource, &tool->focus_resource_list) { @@ -1770,6 +1775,29 @@ static struct weston_tablet_tool_grab_interface default_tablet_tool_grab_interfa default_grab_tablet_tool_cancel, }; +static void +tablet_tool_unmap_sprite(struct weston_tablet_tool *tool) +{ + if (weston_surface_is_mapped(tool->sprite->surface)) + weston_surface_unmap(tool->sprite->surface); + + wl_list_remove(&tool->sprite_destroy_listener.link); + tool->sprite->surface->committed = NULL; + tool->sprite->surface->committed_private = NULL; + weston_view_destroy(tool->sprite); + tool->sprite = NULL; +} + +static void +tablet_tool_handle_sprite_destroy(struct wl_listener *listener, void *data) +{ + struct weston_tablet_tool *tool = + container_of(listener, struct weston_tablet_tool, + sprite_destroy_listener); + + tool->sprite = NULL; +} + WL_EXPORT struct weston_tablet_tool * weston_tablet_tool_create(void) { @@ -1782,6 +1810,9 @@ weston_tablet_tool_create(void) wl_list_init(&tool->resource_list); wl_list_init(&tool->focus_resource_list); + wl_list_init(&tool->sprite_destroy_listener.link); + tool->sprite_destroy_listener.notify = tablet_tool_handle_sprite_destroy; + wl_list_init(&tool->focus_view_listener.link); tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed; @@ -1800,6 +1831,9 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool) { struct wl_resource *resource, *tmp; + if (tool->sprite) + tablet_tool_unmap_sprite(tool); + wl_resource_for_each_safe(resource, tmp, &tool->resource_list) { zwp_tablet_tool_v2_send_removed(resource); wl_resource_set_user_data(resource, NULL); @@ -1816,6 +1850,19 @@ weston_tablet_tool_destroy(struct weston_tablet_tool *tool) free(tool); } +WL_EXPORT void +weston_tablet_tool_cursor_move(struct weston_tablet_tool *tool, + struct weston_coord_global pos) +{ + tool->pos = pos; + + if (tool->sprite) { + weston_view_set_position(tool->sprite, + pos.c.x - tool->hotspot.c.x, + pos.c.y - tool->hotspot.c.y); + weston_view_schedule_repaint(tool->sprite); + } +} static void seat_send_updated_caps(struct weston_seat *seat) @@ -3164,10 +3211,91 @@ notify_tablet_added(struct weston_tablet *tablet) } static void +tablet_tool_cursor_surface_committed(struct weston_surface *es, + struct weston_coord_surface new_origin) +{ + struct weston_tablet_tool *tool = es->committed_private; + struct weston_coord_global pos; + + if (es->width == 0) + return; + + assert(es == tool->sprite->surface); + + tool->hotspot.c = weston_coord_sub(tool->hotspot.c, new_origin.c); + pos.c = weston_coord_sub(tool->pos.c, tool->hotspot.c); + + weston_view_set_position(tool->sprite, pos.c.x, pos.c.y); + + empty_region(&es->pending.input); + empty_region(&es->input); + + if (!weston_surface_is_mapped(es)) { + weston_layer_entry_insert( + &es->compositor->cursor_layer.view_list, + &tool->sprite->layer_link); + weston_view_update_transform(tool->sprite); + es->is_mapped = true; + tool->sprite->is_mapped = true; + } +} + +static void tablet_tool_set_cursor(struct wl_client *client, struct wl_resource *resource, uint32_t serial, struct wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y) { + struct weston_tablet_tool *tool = wl_resource_get_user_data(resource); + struct weston_surface *surface = NULL; + + if (!tool) + return; + + if (surface_resource) + surface = wl_resource_get_user_data(surface_resource); + + if (tool->focus == NULL) + return; + + /* tablet->focus->surface->resource can be NULL. Surfaces like the + * black_surface used in shell.c for fullscreen don't have + * a resource, but can still have focus */ + if (tool->focus->surface->resource == NULL) + return; + + if (wl_resource_get_client(tool->focus->surface->resource) != client) + return; + + if (tool->focus_serial - serial > UINT32_MAX / 2) + return; + + if (surface && tool->sprite && surface != tool->sprite->surface && + surface->committed) { + wl_resource_post_error(surface->resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "surface->configure already set"); + return; + } + + if (tool->sprite) + tablet_tool_unmap_sprite(tool); + + if (!surface) + return; + + wl_signal_add(&surface->destroy_signal, + &tool->sprite_destroy_listener); + surface->committed = tablet_tool_cursor_surface_committed; + surface->committed_private = tool; + tool->sprite = weston_view_create(surface); + tool->hotspot = weston_coord_surface(hotspot_x, hotspot_y, surface); + + if (surface->buffer_ref.buffer) { + struct weston_coord_surface delta = + weston_coord_surface(0, 0, surface); + + tablet_tool_cursor_surface_committed(surface, delta); + } } static void |