diff options
author | Jonas Ådahl <jadahl@gmail.com> | 2019-01-22 09:50:41 +0100 |
---|---|---|
committer | Daniel Stone <daniels@collabora.com> | 2023-03-30 17:14:29 +0000 |
commit | 8f4b141299ec1bd0a36a91e7dbc3d24656e3f5b1 (patch) | |
tree | c91079bcc51824654e811eaf73a5947008f0518e /libweston | |
parent | cc3d30c28bb645a1a4e48814346e052115a74210 (diff) | |
download | weston-8f4b141299ec1bd0a36a91e7dbc3d24656e3f5b1.tar.gz |
desktop: Make popup grab follow keyboard focus semantics
A popup grab is specified to have the top most popup surface gain
keyboard focus. This means the keyboard focus should always follow the
most recent xdg_popup.grab() surface. Make sure this happens by keeping
track of the parent surface in the libweston-desktop popup grab,
updating the keyboard focus when surfaces are added and removed from the
popup chain, and restoring the keyboard focus to the toplevel when there
are no popups anymore.
Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
Diffstat (limited to 'libweston')
-rw-r--r-- | libweston/desktop/internal.h | 2 | ||||
-rw-r--r-- | libweston/desktop/seat.c | 60 | ||||
-rw-r--r-- | libweston/desktop/surface.c | 3 | ||||
-rw-r--r-- | libweston/desktop/xdg-shell-v6.c | 1 | ||||
-rw-r--r-- | libweston/desktop/xdg-shell.c | 1 |
5 files changed, 63 insertions, 4 deletions
diff --git a/libweston/desktop/internal.h b/libweston/desktop/internal.h index 95023f47..c8d09272 100644 --- a/libweston/desktop/internal.h +++ b/libweston/desktop/internal.h @@ -218,6 +218,7 @@ void weston_desktop_surface_unset_relative_to(struct weston_desktop_surface *surface); void weston_desktop_surface_popup_grab(struct weston_desktop_surface *popup, + struct weston_desktop_surface *parent, struct weston_desktop_seat *seat, uint32_t serial); void @@ -230,6 +231,7 @@ struct weston_desktop_surface * weston_desktop_seat_popup_grab_get_topmost_surface(struct weston_desktop_seat *seat); bool weston_desktop_seat_popup_grab_start(struct weston_desktop_seat *seat, + struct weston_desktop_surface *parent, struct wl_client *client, uint32_t serial); void weston_desktop_seat_popup_grab_add_surface(struct weston_desktop_seat *seat, diff --git a/libweston/desktop/seat.c b/libweston/desktop/seat.c index 4887ba9f..ac2cd225 100644 --- a/libweston/desktop/seat.c +++ b/libweston/desktop/seat.c @@ -47,6 +47,8 @@ struct weston_desktop_seat { bool initial_up; struct wl_client *client; struct wl_list surfaces; + struct weston_desktop_surface *grab_surface; + struct wl_listener grab_surface_destroy_listener; } popup_grab; }; @@ -293,8 +295,19 @@ weston_desktop_seat_popup_grab_get_topmost_surface(struct weston_desktop_seat *s return weston_desktop_surface_from_grab_link(grab_link); } +static void +popup_grab_grab_surface_destroy(struct wl_listener *listener, void *data) +{ + struct weston_desktop_seat *seat = + wl_container_of(listener, seat, + popup_grab.grab_surface_destroy_listener); + + seat->popup_grab.grab_surface = NULL; +} + bool weston_desktop_seat_popup_grab_start(struct weston_desktop_seat *seat, + struct weston_desktop_surface *parent, struct wl_client *client, uint32_t serial) { assert(seat == NULL || seat->popup_grab.client == NULL || @@ -317,8 +330,18 @@ weston_desktop_seat_popup_grab_start(struct weston_desktop_seat *seat, seat->popup_grab.client = client; if (keyboard != NULL && - keyboard->grab->interface != &weston_desktop_seat_keyboard_popup_grab_interface) + keyboard->grab->interface != &weston_desktop_seat_keyboard_popup_grab_interface) { + struct weston_surface *parent_surface; + weston_keyboard_start_grab(keyboard, &seat->popup_grab.keyboard); + seat->popup_grab.grab_surface = parent; + + parent_surface = weston_desktop_surface_get_surface(parent); + seat->popup_grab.grab_surface_destroy_listener.notify = + popup_grab_grab_surface_destroy; + wl_signal_add(&parent_surface->destroy_signal, + &seat->popup_grab.grab_surface_destroy_listener); + } if (pointer != NULL && pointer->grab->interface != &weston_desktop_seat_pointer_popup_grab_interface) @@ -349,9 +372,18 @@ weston_desktop_seat_popup_grab_end(struct weston_desktop_seat *seat) } if (keyboard != NULL && - keyboard->grab->interface == &weston_desktop_seat_keyboard_popup_grab_interface) + keyboard->grab->interface == &weston_desktop_seat_keyboard_popup_grab_interface) { + struct weston_desktop_surface *grab_desktop_surface; + struct weston_surface *grab_surface; + weston_keyboard_end_grab(keyboard); + grab_desktop_surface = seat->popup_grab.grab_surface; + grab_surface = + weston_desktop_surface_get_surface(grab_desktop_surface); + weston_keyboard_set_focus(keyboard, grab_surface); + } + if (pointer != NULL && pointer->grab->interface == &weston_desktop_seat_pointer_popup_grab_interface) weston_pointer_end_grab(pointer); @@ -361,15 +393,27 @@ weston_desktop_seat_popup_grab_end(struct weston_desktop_seat *seat) weston_touch_end_grab(touch); seat->popup_grab.client = NULL; + if (seat->popup_grab.grab_surface) { + seat->popup_grab.grab_surface = NULL; + wl_list_remove(&seat->popup_grab.grab_surface_destroy_listener.link); + } } void weston_desktop_seat_popup_grab_add_surface(struct weston_desktop_seat *seat, struct wl_list *link) { + struct weston_desktop_surface *desktop_surface; + struct weston_surface *surface; + assert(seat->popup_grab.client != NULL); wl_list_insert(&seat->popup_grab.surfaces, link); + + desktop_surface = + weston_desktop_seat_popup_grab_get_topmost_surface(seat); + surface = weston_desktop_surface_get_surface(desktop_surface); + weston_keyboard_set_focus(seat->popup_grab.keyboard.keyboard, surface); } void @@ -380,8 +424,18 @@ weston_desktop_seat_popup_grab_remove_surface(struct weston_desktop_seat *seat, wl_list_remove(link); wl_list_init(link); - if (wl_list_empty(&seat->popup_grab.surfaces)) + if (wl_list_empty(&seat->popup_grab.surfaces)) { weston_desktop_seat_popup_grab_end(seat); + } else { + struct weston_desktop_surface *desktop_surface; + struct weston_surface *surface; + + desktop_surface = + weston_desktop_seat_popup_grab_get_topmost_surface(seat); + surface = weston_desktop_surface_get_surface(desktop_surface); + weston_keyboard_set_focus(seat->popup_grab.keyboard.keyboard, + surface); + } } WL_EXPORT void diff --git a/libweston/desktop/surface.c b/libweston/desktop/surface.c index 52e467fd..74707f6a 100644 --- a/libweston/desktop/surface.c +++ b/libweston/desktop/surface.c @@ -849,12 +849,13 @@ weston_desktop_surface_unset_relative_to(struct weston_desktop_surface *surface) void weston_desktop_surface_popup_grab(struct weston_desktop_surface *surface, + struct weston_desktop_surface *parent, struct weston_desktop_seat *seat, uint32_t serial) { struct wl_client *wl_client = weston_desktop_client_get_client(surface->client); - if (weston_desktop_seat_popup_grab_start(seat, wl_client, serial)) + if (weston_desktop_seat_popup_grab_start(seat, parent, wl_client, serial)) weston_desktop_seat_popup_grab_add_surface(seat, &surface->grab_link); else weston_desktop_surface_popup_dismiss(surface); diff --git a/libweston/desktop/xdg-shell-v6.c b/libweston/desktop/xdg-shell-v6.c index aad4ef27..92579ac6 100644 --- a/libweston/desktop/xdg-shell-v6.c +++ b/libweston/desktop/xdg-shell-v6.c @@ -850,6 +850,7 @@ weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client, popup->seat = seat; weston_desktop_surface_popup_grab(popup->base.desktop_surface, + popup->parent->desktop_surface, popup->seat, serial); } diff --git a/libweston/desktop/xdg-shell.c b/libweston/desktop/xdg-shell.c index 3e436163..fb8536ac 100644 --- a/libweston/desktop/xdg-shell.c +++ b/libweston/desktop/xdg-shell.c @@ -955,6 +955,7 @@ weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client, popup->seat = seat; weston_desktop_surface_popup_grab(popup->base.desktop_surface, + popup->parent->desktop_surface, popup->seat, serial); } |