diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index b9d7f664f..5905cb95c 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -581,7 +581,7 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer) meta_wayland_popup_grab_destroy (popup_grab); } -gboolean +MetaWaylandPopup * meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, MetaWaylandSurface *surface) { @@ -589,7 +589,7 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, if (pointer->grab != &pointer->default_grab && !meta_wayland_pointer_grab_is_popup_grab (pointer->grab)) - return FALSE; + return NULL; if (pointer->grab == &pointer->default_grab) { @@ -601,10 +601,7 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, else grab = (MetaWaylandPopupGrab*)pointer->grab; - if (meta_wayland_popup_create (surface, grab) == NULL) - return FALSE; - - return TRUE; + return meta_wayland_popup_create (surface, grab); } void diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index 5dadd5fa3..60125ace7 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -99,8 +99,8 @@ void meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, void meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer); -gboolean meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, - MetaWaylandSurface *popup); +MetaWaylandPopup *meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *popup); void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer); diff --git a/src/wayland/meta-wayland-popup.c b/src/wayland/meta-wayland-popup.c index 9a70ce3a2..cc8b4bd8d 100644 --- a/src/wayland/meta-wayland-popup.c +++ b/src/wayland/meta-wayland-popup.c @@ -61,6 +61,7 @@ struct _MetaWaylandPopup MetaWaylandPopupGrab *grab; MetaWaylandSurface *surface; struct wl_listener surface_destroy_listener; + struct wl_signal destroy_signal; struct wl_list link; }; @@ -180,6 +181,8 @@ meta_wayland_pointer_grab_is_popup_grab (MetaWaylandPointerGrab *grab) void meta_wayland_popup_destroy (MetaWaylandPopup *popup) { + wl_signal_emit (&popup->destroy_signal, popup); + wl_list_remove (&popup->surface_destroy_listener.link); wl_list_remove (&popup->link); g_slice_free (MetaWaylandPopup, popup); @@ -196,6 +199,12 @@ meta_wayland_popup_dismiss (MetaWaylandPopup *popup) meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer); } +struct wl_signal * +meta_wayland_popup_get_destroy_signal (MetaWaylandPopup *popup) +{ + return &popup->destroy_signal; +} + static void on_popup_surface_destroy (struct wl_listener *listener, void *data) @@ -220,6 +229,7 @@ meta_wayland_popup_create (MetaWaylandSurface *surface, popup->grab = grab; popup->surface = surface; popup->surface_destroy_listener.notify = on_popup_surface_destroy; + wl_signal_init (&popup->destroy_signal); if (surface->xdg_popup) { diff --git a/src/wayland/meta-wayland-popup.h b/src/wayland/meta-wayland-popup.h index bba6d56e6..70822250d 100644 --- a/src/wayland/meta-wayland-popup.h +++ b/src/wayland/meta-wayland-popup.h @@ -46,4 +46,6 @@ void meta_wayland_popup_destroy (MetaWaylandPopup *popup); void meta_wayland_popup_dismiss (MetaWaylandPopup *popup); +struct wl_signal *meta_wayland_popup_get_destroy_signal (MetaWaylandPopup *popup); + #endif /* META_WAYLAND_POPUP_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index b7c888d7e..67513014e 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -1021,7 +1021,9 @@ xdg_popup_destructor (struct wl_resource *resource) { MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - destroy_window (surface); + if (surface->popup.popup) + meta_wayland_popup_dismiss (surface->popup.popup); + surface->xdg_popup = NULL; } @@ -1036,6 +1038,17 @@ static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { xdg_popup_destroy, }; +static void +handle_popup_destroyed (struct wl_listener *listener, void *data) +{ + MetaWaylandSurface *surface = + wl_container_of (listener, surface, popup.destroy_listener); + + surface->popup.popup = NULL; + + destroy_window (surface); +} + static void xdg_shell_get_xdg_popup (struct wl_client *client, struct wl_resource *resource, @@ -1053,6 +1066,7 @@ xdg_shell_get_xdg_popup (struct wl_client *client, MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); MetaWindow *window; MetaDisplay *display = meta_get_display (); + MetaWaylandPopup *popup; if (parent_surf == NULL || parent_surf->window == NULL) return; @@ -1107,7 +1121,17 @@ xdg_shell_get_xdg_popup (struct wl_client *client, meta_wayland_surface_set_window (surface, window); meta_window_focus (window, meta_display_get_current_time (display)); - meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); + popup = meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); + if (popup == NULL) + { + destroy_window (surface); + return; + } + + surface->popup.destroy_listener.notify = handle_popup_destroyed; + surface->popup.popup = popup; + wl_signal_add (meta_wayland_popup_get_destroy_signal (popup), + &surface->popup.destroy_listener); } static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = { diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index dd8497a15..0f13dfd16 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -100,6 +100,12 @@ struct _MetaWaylandSurface MetaWaylandSerial acked_configure_serial; gboolean has_set_geometry; + /* xdg_popup */ + struct { + MetaWaylandPopup *popup; + struct wl_listener destroy_listener; + } popup; + /* wl_subsurface stuff. */ struct { MetaWaylandSurface *parent;