[gnome-builder] hover: dismiss hover popover based on crossing event location



commit f8ee2d544ce90fc45ec887b4d847cdbc8c245c65
Author: Christian Hergert <chergert redhat com>
Date:   Mon Jul 23 15:45:34 2018 -0700

    hover: dismiss hover popover based on crossing event location
    
    If we detect that the crossing event is into a child window, we don't want
    to dismiss the popover (it could be a button, webview, etc). However, if
    we are getting a crossing event that is leaving the popover, we want to
    dismiss the hover popover.
    
    This should help in situations where leaving the hover popover into a
    different widget (like the sidebar) left the popover visible.

 src/libide/hover/ide-hover.c | 55 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 43 insertions(+), 12 deletions(-)
---
diff --git a/src/libide/hover/ide-hover.c b/src/libide/hover/ide-hover.c
index 62c068bee..92dceccba 100644
--- a/src/libide/hover/ide-hover.c
+++ b/src/libide/hover/ide-hover.c
@@ -90,8 +90,29 @@ struct _IdeHover
   guint dismiss_source;
 };
 
+static gboolean ide_hover_dismiss_cb (gpointer data);
+
 G_DEFINE_TYPE (IdeHover, ide_hover, G_TYPE_OBJECT)
 
+static void
+ide_hover_queue_dismiss (IdeHover *self)
+{
+  g_assert (IDE_IS_HOVER (self));
+
+  if (self->dismiss_source)
+    g_source_remove (self->dismiss_source);
+
+  /*
+   * Give ourselves just enough time to get the crossing event
+   * into the popover before we try to dismiss the popover.
+   */
+  self->dismiss_source =
+    gdk_threads_add_timeout_full (G_PRIORITY_HIGH,
+                                  1,
+                                  ide_hover_dismiss_cb,
+                                  self, NULL);
+}
+
 static void
 ide_hover_popover_closed_cb (IdeHover        *self,
                              IdeHoverPopover *popover)
@@ -132,6 +153,8 @@ ide_hover_popover_leave_notify_event_cb (IdeHover               *self,
                                          const GdkEventCrossing *event,
                                          IdeHoverPopover        *popover)
 {
+  GtkWidget *child;
+
   g_assert (IDE_IS_HOVER (self));
   g_assert (event != NULL);
   g_assert (IDE_IS_HOVER_POPOVER (popover));
@@ -139,6 +162,25 @@ ide_hover_popover_leave_notify_event_cb (IdeHover               *self,
   if (self->state == IDE_HOVER_STATE_IN_POPOVER)
     self->state = IDE_HOVER_STATE_DISPLAY;
 
+  /* If the window that we are crossing into is not a descendant of our
+   * popover window, then we want to dismiss. This is rather annoying to
+   * track and suffers the same issue as with GtkNotebook tabs containing
+   * buttons (where it's possible to break the prelight state tracking).
+   *
+   * In future Gtk releases, we may be able to use GtkEventControllerMotion.
+   */
+
+  if ((child = gtk_bin_get_child (GTK_BIN (popover))))
+    {
+      GdkRectangle point = { event->x, event->y, 1, 1 };
+      GtkAllocation alloc;
+
+      gtk_widget_get_allocation (child, &alloc);
+
+      if (!dzl_cairo_rectangle_contains_rectangle (&alloc, &point))
+        ide_hover_queue_dismiss (self);
+    }
+
   return GDK_EVENT_PROPAGATE;
 }
 
@@ -467,18 +509,7 @@ ide_hover_leave_notify_event_cb (IdeHover               *self,
   if (should_ignore_event (view, event->window))
     return GDK_EVENT_PROPAGATE;
 
-  if (self->dismiss_source)
-    g_source_remove (self->dismiss_source);
-
-  /*
-   * Give ourselves just enough time to get the crossing event
-   * into the popover before we try to dismiss the popover.
-   */
-  self->dismiss_source =
-    gdk_threads_add_timeout_full (G_PRIORITY_HIGH,
-                                  1,
-                                  ide_hover_dismiss_cb,
-                                  self, NULL);
+  ide_hover_queue_dismiss (self);
 
   return GDK_EVENT_PROPAGATE;
 }


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