mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-06 05:38:05 +02:00
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>
This commit is contained in:
parent
cc3d30c28b
commit
8f4b141299
5 changed files with 63 additions and 4 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue