diff options
author | Lyude Paul <thatslyude@gmail.com> | 2017-12-19 14:03:33 +0530 |
---|---|---|
committer | Daniel Stone <daniels@collabora.com> | 2023-03-31 12:10:26 +0000 |
commit | 6a06669b5802a4821be88a4922d169007d276076 (patch) | |
tree | ced49c3264d1536ac2916e7b63c2f903a57e4e7e | |
parent | 0ced0c62eec9a84b6249dbcb0c72a321293d9e95 (diff) | |
download | weston-6a06669b5802a4821be88a4922d169007d276076.tar.gz |
clients: Add support for tablet cursor motion to window frames in libtoytoolkit
When it comes to a window frame, a tablet tool and cursor act almost
identical; they click things, drag things, etc. The tool type and extra
axes don't serve any use in the context of a window frame, so tablet
pointers share the frame_pointer structures used for the mouse pointer.
Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Lyude Paul <thatslyude@gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com>
Signed-off-by: Bastian Farkas <bfarkas@de.adit-jv.com>
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
-rw-r--r-- | clients/window.c | 54 | ||||
-rw-r--r-- | desktop-shell/shell.c | 279 | ||||
-rw-r--r-- | include/libweston/libweston.h | 5 | ||||
-rw-r--r-- | libweston/input.c | 11 | ||||
-rw-r--r-- | shared/cairo-util.h | 4 | ||||
-rw-r--r-- | shared/frame.c | 38 |
6 files changed, 391 insertions, 0 deletions
diff --git a/clients/window.c b/clients/window.c index 8bc82cb0..1a26e5c6 100644 --- a/clients/window.c +++ b/clients/window.c @@ -2415,6 +2415,54 @@ frame_touch_up_handler(struct widget *widget, frame_handle_status(frame, input, time, THEME_LOCATION_CLIENT_AREA); } +static int +frame_tablet_tool_motion_handler(struct widget *widget, + struct tablet_tool *tool, + float x, float y, + void *data) +{ + struct window_frame *frame = data; + enum theme_location location; + + location = frame_tablet_tool_motion(frame->frame, tool, x, y); + if (frame_status(frame->frame) & FRAME_STATUS_REPAINT) + widget_schedule_redraw(frame->widget); + + frame_get_pointer_image_for_location(data, location); + + return CURSOR_LEFT_PTR; +} + +static void +frame_tablet_tool_down_handler(struct widget *widget, + struct tablet_tool *tool, + void *data) +{ + struct window_frame *frame = data; + enum theme_location location; + uint32_t time = 0; /* FIXME: we should be doing this in the frame + handler where we have the timestamp */ + + /* Map a stylus touch to the left mouse button */ + location = frame_pointer_button(frame->frame, tool, BTN_LEFT, 1); + frame_handle_status(frame, tool->input, time, location); +} + +static void +frame_tablet_tool_up_handler(struct widget *widget, struct tablet_tool *tool, + void *data) +{ + struct window_frame *frame = data; + enum theme_location location; + uint32_t time = 0; /* FIXME: we should be doing this in the frame + handler where we have the timestamp */ + + /* Map the stylus leaving contact with the tablet as releasing the left + * mouse button */ + location = frame_pointer_button(frame->frame, tool, BTN_LEFT, 0); + frame_handle_status(frame, tool->input, time, location); +} + struct widget * window_frame_create(struct window *window, void *data) { @@ -2446,6 +2494,12 @@ window_frame_create(struct window *window, void *data) widget_set_button_handler(frame->widget, frame_button_handler); widget_set_touch_down_handler(frame->widget, frame_touch_down_handler); widget_set_touch_up_handler(frame->widget, frame_touch_up_handler); + widget_set_tablet_tool_axis_handlers(frame->widget, + frame_tablet_tool_motion_handler, + NULL, NULL, NULL, + NULL, NULL, NULL); + widget_set_tablet_tool_down_handler(frame->widget, frame_tablet_tool_down_handler); + widget_set_tablet_tool_up_handler(frame->widget, frame_tablet_tool_up_handler); window->frame = frame; diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index c7ab2256..8061b3b9 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -161,6 +161,13 @@ struct shell_touch_grab { struct weston_touch *touch; }; +struct shell_tablet_tool_grab { + struct weston_tablet_tool_grab grab; + struct shell_surface *shsurf; + struct wl_listener shsurf_destroy_listener; + struct weston_tablet_tool *tool; +}; + struct weston_move_grab { struct shell_grab base; wl_fixed_t dx, dy; @@ -173,6 +180,11 @@ struct weston_touch_move_grab { wl_fixed_t dx, dy; }; +struct weston_tablet_tool_move_grab { + struct shell_tablet_tool_grab base; + wl_fixed_t dx, dy; +}; + struct rotate_grab { struct shell_grab base; struct weston_matrix rotation; @@ -190,10 +202,15 @@ struct shell_seat { struct wl_listener caps_changed_listener; struct wl_listener pointer_focus_listener; struct wl_listener keyboard_focus_listener; + struct wl_listener tablet_tool_added_listener; struct wl_list link; /** shell::seat_list */ }; +struct tablet_tool_listener { + struct wl_listener base; + struct wl_listener removed_listener; +}; static struct weston_view * shell_fade_create_fade_out_view(struct shell_surface *shsurf, @@ -446,6 +463,42 @@ shell_touch_grab_end(struct shell_touch_grab *grab) weston_touch_end_grab(grab->touch); } +static void +shell_tablet_tool_grab_start(struct shell_tablet_tool_grab *grab, + const struct weston_tablet_tool_grab_interface *interface, + struct shell_surface *shsurf, + struct weston_tablet_tool *tool) +{ + struct desktop_shell *shell = shsurf->shell; + + weston_seat_break_desktop_grabs(tool->seat); + + grab->grab.interface = interface; + grab->shsurf = shsurf; + grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf; + wl_signal_add(&shsurf->destroy_signal, &grab->shsurf_destroy_listener); + + grab->tool = tool; + shsurf->grabbed = 1; + + weston_tablet_tool_start_grab(tool, &grab->grab); + if (shell->child.desktop_shell) + weston_tablet_tool_set_focus(tool, + get_default_view(shell->grab_surface), + 0); +} + +static void +shell_tablet_tool_grab_end(struct shell_tablet_tool_grab *grab) +{ + if (grab->shsurf) { + wl_list_remove(&grab->shsurf_destroy_listener.link); + grab->shsurf->grabbed = 0; + } + + weston_tablet_tool_end_grab(grab->tool); +} + static enum animation_type get_animation_type(char *animation) { @@ -1144,6 +1197,148 @@ struct weston_resize_grab { }; static void +tablet_tool_noop_grab_proximity_in(struct weston_tablet_tool_grab *grab, + const struct timespec *time, + struct weston_tablet *tablet) +{ +} + +static void +tablet_tool_move_grab_proximity_out(struct weston_tablet_tool_grab *grab, + const struct timespec *time) +{ + struct weston_tablet_tool_move_grab *move = + (struct weston_tablet_tool_move_grab *)grab; + + shell_tablet_tool_grab_end(&move->base); + free(grab); +} + +static void +tablet_tool_move_grab_up(struct weston_tablet_tool_grab *grab, + const struct timespec *time) +{ + struct weston_tablet_tool_move_grab *move = + (struct weston_tablet_tool_move_grab *)grab; + + shell_tablet_tool_grab_end(&move->base); + free(grab); +} + +static void +tablet_tool_noop_grab_down(struct weston_tablet_tool_grab *grab, + const struct timespec *time) +{ +} + +static void +tablet_tool_move_grab_motion(struct weston_tablet_tool_grab *grab, + const struct timespec *time, + struct weston_coord_global pos) +{ + struct weston_tablet_tool_move_grab *move = + (struct weston_tablet_tool_move_grab *)grab; + struct shell_surface *shsurf = move->base.shsurf; + struct weston_surface *es; + + weston_tablet_tool_cursor_move(grab->tool, pos); + + if (!shsurf) + return; + + es = weston_desktop_surface_get_surface(shsurf->desktop_surface); + weston_view_set_position(shsurf->view, + pos.c.x + wl_fixed_to_double(move->dx), + pos.c.y + wl_fixed_to_double(move->dy)); + weston_compositor_schedule_repaint(es->compositor); +} + +static void +tablet_tool_noop_grab_pressure(struct weston_tablet_tool_grab *grab, + const struct timespec *time, + uint32_t pressure) +{ +} + +static void +tablet_tool_noop_grab_distance(struct weston_tablet_tool_grab *grab, + const struct timespec *time, + uint32_t distance) +{ +} + +static void +tablet_tool_noop_grab_tilt(struct weston_tablet_tool_grab *grab, + const struct timespec *time, + int32_t tilt_x, int32_t tilt_y) +{ +} + +static void tablet_tool_noop_grab_button(struct weston_tablet_tool_grab *grab, + const struct timespec *time, uint32_t button, + uint32_t state) +{ +} + +static void +tablet_tool_noop_grab_frame(struct weston_tablet_tool_grab *grab, + const struct timespec *time) +{ +} + +static void +tablet_tool_move_grab_cancel(struct weston_tablet_tool_grab *grab) +{ + struct weston_tablet_tool_move_grab *move = + (struct weston_tablet_tool_move_grab *)grab; + + shell_tablet_tool_grab_end(&move->base); + free(grab); +} + +static struct weston_tablet_tool_grab_interface tablet_tool_move_grab_interface = { + tablet_tool_noop_grab_proximity_in, + tablet_tool_move_grab_proximity_out, + tablet_tool_move_grab_motion, + tablet_tool_noop_grab_down, + tablet_tool_move_grab_up, + tablet_tool_noop_grab_pressure, + tablet_tool_noop_grab_distance, + tablet_tool_noop_grab_tilt, + tablet_tool_noop_grab_button, + tablet_tool_noop_grab_frame, + tablet_tool_move_grab_cancel, +}; + +static int +surface_tablet_tool_move(struct shell_surface *shsurf, struct weston_tablet_tool *tool) +{ + struct weston_tablet_tool_move_grab *move; + struct weston_coord offset; + + if (!shsurf) + return -1; + + if (shsurf->state.fullscreen || shsurf->state.maximized) + return 0; + + move = malloc(sizeof(*move)); + if (!move) + return -1; + + offset = weston_coord_sub(shsurf->view->geometry.pos_offset, + tool->grab_pos.c); + move->dx = wl_fixed_from_double(offset.x); + move->dy = wl_fixed_from_double(offset.y); + + shell_tablet_tool_grab_start(&move->base, &tablet_tool_move_grab_interface, + shsurf, tool); + + return 0; +} + + +static void resize_grab_motion(struct weston_pointer_grab *grab, const struct timespec *time, struct weston_pointer_motion_event *event) @@ -1444,6 +1639,26 @@ sync_surface_activated_state(struct shell_surface *shsurf) } static void +handle_tablet_tool_focus(struct wl_listener *listener, void *data) +{ + struct weston_tablet_tool *tool = data; + struct weston_view *view = tool->focus; + struct shell_surface *shsurf; + struct weston_desktop_client *client; + + if (!view) + return; + + shsurf = get_shell_surface(view->surface); + if (!shsurf) + return; + + client = weston_desktop_surface_get_client(shsurf->desktop_surface); + + weston_desktop_client_ping(client); +} + +static void shell_surface_deactivate(struct shell_surface *shsurf) { if (--shsurf->focus_count == 0) @@ -1779,12 +1994,44 @@ desktop_shell_destroy_seat(struct shell_seat *shseat) wl_list_remove(&shseat->caps_changed_listener.link); wl_list_remove(&shseat->pointer_focus_listener.link); wl_list_remove(&shseat->seat_destroy_listener.link); + wl_list_remove(&shseat->tablet_tool_added_listener.link); wl_list_remove(&shseat->link); free(shseat); } static void +destroy_tablet_tool_listener(struct wl_listener *listener, void *data) +{ + struct tablet_tool_listener *tool_listener = + container_of(listener, struct tablet_tool_listener, removed_listener); + + wl_list_remove(&tool_listener->removed_listener.link); + wl_list_remove(&tool_listener->base.link); + free(tool_listener); +} + +static void +handle_tablet_tool_added(struct wl_listener *listener, void *data) +{ + struct weston_tablet_tool *tool = data; + struct tablet_tool_listener *tool_listener; + + tool_listener = malloc(sizeof *tool_listener); + if (!tool_listener) { + weston_log("no memory to allocate to shell seat tablet listener\n"); + return; + } + + tool_listener->removed_listener.notify = destroy_tablet_tool_listener; + wl_signal_add(&tool->removed_signal, + &tool_listener->removed_listener); + + tool_listener->base.notify = handle_tablet_tool_focus; + wl_signal_add(&tool->focus_signal, &tool_listener->base); +} + +static void destroy_shell_seat(struct wl_listener *listener, void *data) { struct shell_seat *shseat = @@ -1817,6 +2064,7 @@ static struct shell_seat * create_shell_seat(struct desktop_shell *shell, struct weston_seat *seat) { struct shell_seat *shseat; + struct weston_tablet_tool *tool; shseat = calloc(1, sizeof *shseat); if (!shseat) { @@ -1835,6 +2083,25 @@ create_shell_seat(struct desktop_shell *shell, struct weston_seat *seat) shseat->pointer_focus_listener.notify = handle_pointer_focus; wl_list_init(&shseat->pointer_focus_listener.link); + shseat->tablet_tool_added_listener.notify = handle_tablet_tool_added; + wl_list_init(&shseat->tablet_tool_added_listener.link); + + wl_list_for_each(tool, &seat->tablet_tool_list, link) { + struct tablet_tool_listener *listener = malloc(sizeof *listener); + + if (!listener) { + weston_log("no memory to allocate to shell seat tablet listener\n"); + break; + } + + listener->removed_listener.notify = destroy_tablet_tool_listener; + wl_signal_add(&tool->removed_signal, + &listener->removed_listener); + + listener->base.notify = handle_tablet_tool_focus; + wl_signal_add(&tool->focus_signal, &listener->base); + } + shseat->caps_changed_listener.notify = shell_seat_caps_changed; wl_signal_add(&seat->updated_caps_signal, &shseat->caps_changed_listener); @@ -2303,6 +2570,18 @@ desktop_surface_move(struct weston_desktop_surface *desktop_surface, if ((focus == surface) && (surface_touch_move(shsurf, touch) < 0)) wl_resource_post_no_memory(resource); + } else if (!wl_list_empty(&seat->tablet_tool_list)) { + struct weston_tablet_tool *tool; + + wl_list_for_each(tool, &seat->tablet_tool_list, link) { + if (tool->focus && tool->grab_serial == serial) { + focus = weston_surface_get_main_surface( + tool->focus->surface); + if (focus == surface && + surface_tablet_tool_move(shsurf, tool) < 0) + wl_resource_post_no_memory(resource); + } + } } } diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index 207cf771..b6fa8bd6 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -914,6 +914,10 @@ struct weston_tablet_tool { struct wl_listener sprite_destroy_listener; struct weston_coord_global pos; + struct weston_coord_global grab_pos; + + struct wl_signal focus_signal; + struct wl_signal removed_signal; }; struct weston_tablet { @@ -1176,6 +1180,7 @@ struct weston_seat { struct wl_list tablet_list; struct wl_list tablet_tool_list; struct wl_list tablet_seat_resource_list; + struct wl_signal tablet_tool_added_signal; }; enum { diff --git a/libweston/input.c b/libweston/input.c index 4f3c7ec1..d8bc1116 100644 --- a/libweston/input.c +++ b/libweston/input.c @@ -1535,6 +1535,8 @@ weston_tablet_tool_set_focus(struct weston_tablet_tool *tool, &tool->focus_resource_listener); tool->focus = view; tool->focus_view_listener.notify = tablet_tool_focus_view_destroyed; + + wl_signal_emit(&tool->focus_signal, tool); } WL_EXPORT void @@ -1823,6 +1825,9 @@ weston_tablet_tool_create(void) tool->default_grab.tool = tool; tool->grab = &tool->default_grab; + wl_signal_init(&tool->focus_signal); + wl_signal_init(&tool->removed_signal); + return tool; } @@ -3361,6 +3366,8 @@ notify_tablet_tool_added(struct weston_tablet_tool *tool) struct weston_seat *seat = tool->seat; struct wl_client *client; + wl_signal_emit(&seat->tablet_tool_added_signal, tool); + wl_resource_for_each(tablet_seat_resource, &seat->tablet_seat_resource_list) { client = wl_resource_get_client(tablet_seat_resource); @@ -3469,6 +3476,7 @@ notify_tablet_tool_down(struct weston_tablet_tool *tool, tool->tip_is_down = true; tool->grab_serial = wl_display_get_serial(compositor->wl_display); + tool->grab_pos = tool->pos; grab->interface->down(grab, time); } @@ -4221,6 +4229,8 @@ weston_seat_release_pointer(struct weston_seat *seat) WL_EXPORT void weston_seat_release_tablet_tool(struct weston_tablet_tool *tool) { + wl_signal_emit(&tool->removed_signal, tool); + weston_tablet_tool_destroy(tool); } @@ -4315,6 +4325,7 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec, wl_list_init(&seat->tablet_seat_resource_list); wl_list_init(&seat->tablet_list); wl_list_init(&seat->tablet_tool_list); + wl_signal_init(&seat->tablet_tool_added_signal); seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, MIN(wl_seat_interface.version, 7), diff --git a/shared/cairo-util.h b/shared/cairo-util.h index 4573d54a..0926fc61 100644 --- a/shared/cairo-util.h +++ b/shared/cairo-util.h @@ -241,6 +241,10 @@ frame_double_touch_down(struct frame *frame, void *data, int32_t id, void frame_double_touch_up(struct frame *frame, void *data, int32_t id); +/* May set FRAME_STATUS_REPAINT */ +enum theme_location +frame_tablet_tool_motion(struct frame *frame, void *pointer, int x, int y); + void frame_repaint(struct frame *frame, cairo_t *cr); diff --git a/shared/frame.c b/shared/frame.c index 6599e96b..8094b37c 100644 --- a/shared/frame.c +++ b/shared/frame.c @@ -1015,6 +1015,44 @@ frame_double_touch_up(struct frame *frame, void *data, int32_t id) } } +enum theme_location +frame_tablet_tool_motion(struct frame *frame, void *data, int x, int y) +{ + struct frame_pointer *tool_pointer = frame_pointer_get(frame, data); + struct frame_button *button, + *prev_button = tool_pointer->hover_button; + enum theme_location location; + + location = theme_get_location(frame->theme, tool_pointer->x, + tool_pointer->y, frame->width, + frame->height, + frame->flags & FRAME_FLAG_MAXIMIZED ? + THEME_FRAME_MAXIMIZED : 0); + + if (!tool_pointer) + return location; + + tool_pointer->x = x; + tool_pointer->y = y; + + button = frame_find_button(frame, x, y); + + if (prev_button) { + if (prev_button == button) + /* The button hasn't changed so we're done here */ + return location; + else + frame_button_leave(prev_button, tool_pointer); + } + + if (button) + frame_button_enter(button); + + tool_pointer->hover_button = button; + + return location; +} + void frame_repaint(struct frame *frame, cairo_t *cr) { |