diff options
-rw-r--r-- | include/wlr/types/wlr_wl_shell.h | 1 | ||||
-rw-r--r-- | types/wlr_wl_shell.c | 47 |
2 files changed, 46 insertions, 2 deletions
diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index bea92b8b..6f6d0182 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -71,6 +71,7 @@ struct wlr_wl_shell_surface { struct wlr_wl_shell_surface *parent; struct wl_list popup_link; struct wl_list popups; + bool popup_mapped; struct { struct wl_signal destroy; diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 5851c63a..022f865a 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -17,10 +17,38 @@ static void shell_pointer_grab_end(struct wlr_seat_pointer_grab *grab) { struct wlr_wl_shell_surface *popup, *tmp = NULL; wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { - wl_shell_surface_send_popup_done(popup->resource); + if (popup->popup_mapped) { + wl_shell_surface_send_popup_done(popup->resource); + popup->popup_mapped = false; + } } - wlr_seat_pointer_end_grab(grab->seat); + + if (grab->seat->pointer_state.grab == grab) { + wlr_seat_pointer_end_grab(grab->seat); + } +} + +static void shell_pointer_grab_maybe_end(struct wlr_seat_pointer_grab *grab) { + struct wlr_wl_shell_popup_grab *popup_grab = grab->data; + + if (grab->seat->pointer_state.grab != grab) { + return; + } + + bool has_mapped = false; + + struct wlr_wl_shell_surface *popup, *tmp = NULL; + wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { + if (popup->popup_mapped) { + has_mapped = true; + break; + } + } + + if (!has_mapped) { + shell_pointer_grab_end(grab); + } } static void shell_pointer_grab_enter(struct wlr_seat_pointer_grab *grab, @@ -307,6 +335,7 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, surface->transient_state->y = y; shell_surface_popup_set_parent(surface, wl_parent); grab->client = surface->client; + surface->popup_mapped = true; wlr_seat_pointer_start_grab(seat_handle->wlr_seat, &grab->pointer_grab); return; } @@ -337,6 +366,7 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, shell_surface_popup_set_parent(surface, wl_parent); grab->client = surface->client; wl_list_insert(&grab->popups, &surface->grab_link); + surface->popup_mapped = true; wlr_seat_pointer_start_grab(seat_handle->wlr_seat, &grab->pointer_grab); } @@ -457,6 +487,16 @@ static void handle_wlr_surface_committed(struct wl_listener *listener, surface->configured = true; wl_signal_emit(&surface->shell->events.new_surface, surface); } + + if (surface->popup_mapped && + surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP && + !surface->surface->texture->valid) { + surface->popup_mapped = false; + struct wlr_wl_shell_popup_grab *grab = + shell_popup_grab_from_seat(surface->shell, + surface->popup_state->seat); + shell_pointer_grab_maybe_end(&grab->pointer_grab); + } } static int shell_surface_ping_timeout(void *user_data) { @@ -611,6 +651,9 @@ struct wlr_wl_shell_surface *wlr_wl_shell_surface_popup_at( double *popup_sx, double *popup_sy) { struct wlr_wl_shell_surface *popup; wl_list_for_each(popup, &surface->popups, popup_link) { + if (!popup->popup_mapped) { + continue; + } double _popup_sx = popup->transient_state->x; double _popup_sy = popup->transient_state->y; int popup_width = |