aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_wl_shell.h1
-rw-r--r--types/wlr_wl_shell.c47
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 =