wayland: Unmap popup windows when a popup chain is dismissed

When dismissing a popup grab, always unmap every popup window in the
chain, instead of relying on the surfaces and xdg_popups being
destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=744452
This commit is contained in:
Jonas Ådahl 2015-02-12 11:13:55 +08:00
parent 768286bffb
commit be77874ec9
6 changed files with 49 additions and 10 deletions

View File

@ -581,7 +581,7 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
meta_wayland_popup_grab_destroy (popup_grab); meta_wayland_popup_grab_destroy (popup_grab);
} }
gboolean MetaWaylandPopup *
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface) MetaWaylandSurface *surface)
{ {
@ -589,7 +589,7 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
if (pointer->grab != &pointer->default_grab && if (pointer->grab != &pointer->default_grab &&
!meta_wayland_pointer_grab_is_popup_grab (pointer->grab)) !meta_wayland_pointer_grab_is_popup_grab (pointer->grab))
return FALSE; return NULL;
if (pointer->grab == &pointer->default_grab) if (pointer->grab == &pointer->default_grab)
{ {
@ -601,10 +601,7 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
else else
grab = (MetaWaylandPopupGrab*)pointer->grab; grab = (MetaWaylandPopupGrab*)pointer->grab;
if (meta_wayland_popup_create (surface, grab) == NULL) return meta_wayland_popup_create (surface, grab);
return FALSE;
return TRUE;
} }
void void

View File

@ -99,8 +99,8 @@ void meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
void meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer); void meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
gboolean meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, MetaWaylandPopup *meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *popup); MetaWaylandSurface *popup);
void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer); void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer);

View File

@ -61,6 +61,7 @@ struct _MetaWaylandPopup
MetaWaylandPopupGrab *grab; MetaWaylandPopupGrab *grab;
MetaWaylandSurface *surface; MetaWaylandSurface *surface;
struct wl_listener surface_destroy_listener; struct wl_listener surface_destroy_listener;
struct wl_signal destroy_signal;
struct wl_list link; struct wl_list link;
}; };
@ -180,6 +181,8 @@ meta_wayland_pointer_grab_is_popup_grab (MetaWaylandPointerGrab *grab)
void void
meta_wayland_popup_destroy (MetaWaylandPopup *popup) 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->surface_destroy_listener.link);
wl_list_remove (&popup->link); wl_list_remove (&popup->link);
g_slice_free (MetaWaylandPopup, popup); 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); 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 static void
on_popup_surface_destroy (struct wl_listener *listener, on_popup_surface_destroy (struct wl_listener *listener,
void *data) void *data)
@ -220,6 +229,7 @@ meta_wayland_popup_create (MetaWaylandSurface *surface,
popup->grab = grab; popup->grab = grab;
popup->surface = surface; popup->surface = surface;
popup->surface_destroy_listener.notify = on_popup_surface_destroy; popup->surface_destroy_listener.notify = on_popup_surface_destroy;
wl_signal_init (&popup->destroy_signal);
if (surface->xdg_popup) if (surface->xdg_popup)
{ {

View File

@ -46,4 +46,6 @@ void meta_wayland_popup_destroy (MetaWaylandPopup *popup);
void meta_wayland_popup_dismiss (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 */ #endif /* META_WAYLAND_POPUP_H */

View File

@ -1021,7 +1021,9 @@ xdg_popup_destructor (struct wl_resource *resource)
{ {
MetaWaylandSurface *surface = wl_resource_get_user_data (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; surface->xdg_popup = NULL;
} }
@ -1036,6 +1038,17 @@ static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
xdg_popup_destroy, 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 static void
xdg_shell_get_xdg_popup (struct wl_client *client, xdg_shell_get_xdg_popup (struct wl_client *client,
struct wl_resource *resource, 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); MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWindow *window; MetaWindow *window;
MetaDisplay *display = meta_get_display (); MetaDisplay *display = meta_get_display ();
MetaWaylandPopup *popup;
if (parent_surf == NULL || parent_surf->window == NULL) if (parent_surf == NULL || parent_surf->window == NULL)
return; return;
@ -1107,7 +1121,17 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
meta_wayland_surface_set_window (surface, window); meta_wayland_surface_set_window (surface, window);
meta_window_focus (window, meta_display_get_current_time (display)); 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 = { static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = {

View File

@ -100,6 +100,12 @@ struct _MetaWaylandSurface
MetaWaylandSerial acked_configure_serial; MetaWaylandSerial acked_configure_serial;
gboolean has_set_geometry; gboolean has_set_geometry;
/* xdg_popup */
struct {
MetaWaylandPopup *popup;
struct wl_listener destroy_listener;
} popup;
/* wl_subsurface stuff. */ /* wl_subsurface stuff. */
struct { struct {
MetaWaylandSurface *parent; MetaWaylandSurface *parent;