[gtk/wip/matthiasc/popup5: 80/108] surface: Add gdk_surface_show_with_auto_dismissal



commit d8ae6c1b88b2bed5ed09ded467ef7a5dec939dce
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Apr 22 21:31:33 2019 +0000

    surface: Add gdk_surface_show_with_auto_dismissal
    
    This api is meant to mimic xdg-popover.grab - we
    show the surface, and dismiss it when we get events
    on other surfaces. For foreign surfaces, the compositor
    handles that for us; for our own, we check outselves
    before delivering events to GTK.

 docs/reference/gdk/gdk4-sections.txt |  1 +
 gdk/gdksurface.c                     | 79 +++++++++++++++++++++++++++++++++++-
 gdk/gdksurface.h                     |  4 ++
 gdk/gdksurfaceprivate.h              |  1 +
 4 files changed, 84 insertions(+), 1 deletion(-)
---
diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt
index e3fa979d66..6338ab03cc 100644
--- a/docs/reference/gdk/gdk4-sections.txt
+++ b/docs/reference/gdk/gdk4-sections.txt
@@ -186,6 +186,7 @@ gdk_surface_get_surface_type
 gdk_surface_get_display
 gdk_surface_show
 gdk_surface_show_unraised
+gdk_surface_show_with_auto_dismissal
 gdk_surface_hide
 gdk_surface_is_destroyed
 gdk_surface_is_visible
diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c
index 237406bb12..569d751c81 100644
--- a/gdk/gdksurface.c
+++ b/gdk/gdksurface.c
@@ -1762,7 +1762,10 @@ gdk_surface_show_internal (GdkSurface *surface, gboolean raise)
     gdk_surface_raise_internal (surface);
 
   if (!was_mapped)
-    gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+    {
+      gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+      surface->auto_dismissal = FALSE;
+    }
 
   did_show = _gdk_surface_update_viewable (surface);
 
@@ -4183,10 +4186,54 @@ gdk_synthesize_surface_state (GdkSurface     *surface,
   gdk_surface_set_state (surface, (surface->state | set_flags) & ~unset_flags);
 }
 
+static gboolean
+check_auto_dismissal (GdkEvent *event)
+{
+  GdkDisplay *display;
+  GdkDevice *device;
+  GdkSurface *grab_surface;
+
+ switch ((guint) gdk_event_get_event_type (event))
+    {
+    case GDK_BUTTON_PRESS:
+#if 0
+    // FIXME: we need to ignore the release that is paired
+    // with the press starting the grab - due to implicit
+    // grabs, it will be delivered to the same place as the
+    // press, and will cause the auto dismissal to be triggered.
+    case GDK_BUTTON_RELEASE:
+#endif
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
+    case GDK_TOUCHPAD_SWIPE:
+    case GDK_TOUCHPAD_PINCH:
+      display = gdk_event_get_display (event);
+      device = gdk_event_get_device (event);
+      if (gdk_device_grab_info (display, device, &grab_surface, NULL))
+        {
+          if (grab_surface != gdk_event_get_surface (event) &&
+              grab_surface->auto_dismissal)
+            {
+              gdk_surface_hide (grab_surface);
+              return TRUE;
+            }
+        }
+      break;
+    default:;
+    }
+
+  return FALSE;
+}
+
 gboolean
 gdk_surface_handle_event (GdkEvent *event)
 {
   gboolean handled = FALSE;
+
+  if (check_auto_dismissal (event))
+    return TRUE;
+
   if (gdk_event_get_event_type (event) == GDK_CONFIGURE)
     {
       g_signal_emit (gdk_event_get_surface (event), signals[SIZE_CHANGED], 0,
@@ -4200,3 +4247,33 @@ gdk_surface_handle_event (GdkEvent *event)
 
   return handled;
 }
+
+static void
+grab_prepare_func (GdkSeat    *seat,
+                   GdkSurface *surface,
+                   gpointer    data)
+{
+  gdk_surface_show (surface);
+  surface->auto_dismissal = TRUE;
+}
+
+/**
+ * gdk_surface_show_with_auto_dismissal:
+ * @surface: a #GdkSurface
+ * @seat: the seat to grab on
+ *
+ * Show the surface, like gdk_surface_show(), but also
+ * take a grab and hide the surface when we encounter
+ * button presses or touch events outside the surface.
+ */
+void
+gdk_surface_show_with_auto_dismissal (GdkSurface *surface,
+                                      GdkSeat    *seat)
+{
+  gdk_seat_grab (seat,
+                 surface,
+                 GDK_SEAT_CAPABILITY_ALL,
+                 TRUE,
+                 NULL, NULL,
+                 grab_prepare_func, NULL);
+}
diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h
index 938c59ba17..956870d040 100644
--- a/gdk/gdksurface.h
+++ b/gdk/gdksurface.h
@@ -443,6 +443,10 @@ GDK_AVAILABLE_IN_ALL
 void          gdk_surface_hide                  (GdkSurface     *surface);
 GDK_AVAILABLE_IN_ALL
 void          gdk_surface_show_unraised         (GdkSurface     *surface);
+GDK_AVAILABLE_IN_ALL
+void          gdk_surface_show_with_auto_dismissal (GdkSurface *surface,
+                                                    GdkSeat    *seat);
+
 GDK_AVAILABLE_IN_ALL
 void          gdk_surface_move                  (GdkSurface     *surface,
                                                  gint           x,
diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h
index 25319c6b38..b03cc5ccd1 100644
--- a/gdk/gdksurfaceprivate.h
+++ b/gdk/gdksurfaceprivate.h
@@ -69,6 +69,7 @@ struct _GdkSurface
   guint viewable : 1; /* mapped and all parents mapped */
   guint in_update : 1;
   guint frame_clock_events_paused : 1;
+  guint auto_dismissal : 1;
 
   guint update_and_descendants_freeze_count;
 


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