[mutter] wayland: Unmap popup windows when a popup chain is dismissed



commit be77874ec92dd7ff936955ac89ce67db5edc2a08
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Feb 12 11:13:55 2015 +0800

    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

 src/wayland/meta-wayland-pointer.c |    9 +++------
 src/wayland/meta-wayland-pointer.h |    4 ++--
 src/wayland/meta-wayland-popup.c   |   10 ++++++++++
 src/wayland/meta-wayland-popup.h   |    2 ++
 src/wayland/meta-wayland-surface.c |   28 ++++++++++++++++++++++++++--
 src/wayland/meta-wayland-surface.h |    6 ++++++
 6 files changed, 49 insertions(+), 10 deletions(-)
---
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
index b9d7f66..5905cb9 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 5dadd5f..60125ac 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 9a70ce3..cc8b4bd 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 bba6d56..7082225 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 b7c888d..6751301 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;
 }
 
@@ -1037,6 +1039,17 @@ static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = {
 };
 
 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,
                          uint32_t id,
@@ -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 dd8497a..0f13dfd 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]