diff --git a/libweston/desktop/internal.h b/libweston/desktop/internal.h index 95023f477..c8d09272c 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 4887ba9f2..ac2cd2252 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 52e467fd4..74707f6a6 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 aad4ef279..92579ac60 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 3e4361634..fb8536ac4 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); }