[gtk+/wip/attente/popup-at: 37/40] gtkmenu: position menu using gdk_window_move_to_rect ()



commit 2dc9a1bcae06c2b56151e4aaa80665c5389da330
Author: William Hua <william hua canonical com>
Date:   Wed Jun 29 16:42:42 2016 -0400

    gtkmenu: position menu using gdk_window_move_to_rect ()
    
    https://bugzilla.gnome.org/show_bug.cgi?id=756579

 gtk/gtkmenu.c |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 120 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 36df032..20c670b 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -137,6 +137,7 @@
 
 
 #include "a11y/gtkmenuaccessible.h"
+#include "gdk/gdk-private.h"
 
 #define NAVIGATION_REGION_OVERSHOOT 50  /* How much the navigation region
                                          * extends below the submenu
@@ -1357,6 +1358,23 @@ gtk_menu_init (GtkMenu *menu)
 }
 
 static void
+moved_to_rect_cb (GdkWindow          *window,
+                  const GdkRectangle *flipped_rect,
+                  const GdkRectangle *final_rect,
+                  gboolean            flipped_x,
+                  gboolean            flipped_y,
+                  GtkMenu            *menu)
+{
+  g_signal_emit (menu,
+                 menu_signals[POPPED_UP],
+                 0,
+                 flipped_rect,
+                 final_rect,
+                 flipped_x,
+                 flipped_y);
+}
+
+static void
 gtk_menu_destroy (GtkWidget *widget)
 {
   GtkMenu *menu = GTK_MENU (widget);
@@ -1383,7 +1401,10 @@ gtk_menu_destroy (GtkWidget *widget)
   g_clear_object (&priv->accel_group);
 
   if (priv->toplevel)
-    gtk_widget_destroy (priv->toplevel);
+    {
+      g_signal_handlers_disconnect_by_func (priv->toplevel, moved_to_rect_cb, menu);
+      gtk_widget_destroy (priv->toplevel);
+    }
 
   if (priv->tearoff_window)
     gtk_widget_destroy (priv->tearoff_window);
@@ -4814,8 +4835,8 @@ gtk_menu_deactivate (GtkMenuShell *menu_shell)
 }
 
 static void
-gtk_menu_position (GtkMenu  *menu,
-                   gboolean  set_scroll_offset)
+gtk_menu_position_legacy (GtkMenu  *menu,
+                          gboolean  set_scroll_offset)
 {
   GtkMenuPrivate *priv = menu->priv;
   GtkWidget *widget;
@@ -5053,6 +5074,102 @@ gtk_menu_position (GtkMenu  *menu,
     priv->scroll_offset = scroll_offset;
 }
 
+static GdkGravity
+get_horizontally_flipped_anchor (GdkGravity anchor)
+{
+  switch (anchor)
+    {
+    case GDK_GRAVITY_STATIC:
+    case GDK_GRAVITY_NORTH_WEST:
+      return GDK_GRAVITY_NORTH_EAST;
+    case GDK_GRAVITY_NORTH:
+      return GDK_GRAVITY_NORTH;
+    case GDK_GRAVITY_NORTH_EAST:
+      return GDK_GRAVITY_NORTH_WEST;
+    case GDK_GRAVITY_WEST:
+      return GDK_GRAVITY_EAST;
+    case GDK_GRAVITY_CENTER:
+      return GDK_GRAVITY_CENTER;
+    case GDK_GRAVITY_EAST:
+      return GDK_GRAVITY_WEST;
+    case GDK_GRAVITY_SOUTH_WEST:
+      return GDK_GRAVITY_SOUTH_EAST;
+    case GDK_GRAVITY_SOUTH:
+      return GDK_GRAVITY_SOUTH;
+    case GDK_GRAVITY_SOUTH_EAST:
+      return GDK_GRAVITY_SOUTH_WEST;
+    }
+
+  g_warning ("unknown GdkGravity: %d", anchor);
+  return anchor;
+}
+
+static void
+gtk_menu_position (GtkMenu  *menu,
+                   gboolean  set_scroll_offset)
+{
+  GtkMenuPrivate *priv = menu->priv;
+  GdkWindow *rect_window = NULL;
+  GdkRectangle rect;
+  GtkTextDirection text_direction = GTK_TEXT_DIR_NONE;
+  GdkGravity rect_anchor;
+  GdkGravity menu_anchor;
+  GdkWindow *toplevel;
+
+  if (priv->rect_window)
+    {
+      rect_window = priv->rect_window;
+      rect = priv->rect;
+    }
+  else if (priv->widget)
+    {
+      rect_window = gtk_widget_get_window (priv->widget);
+      gtk_widget_get_allocation (priv->widget, &rect);
+      text_direction = gtk_widget_get_direction (priv->widget);
+    }
+
+  if (rect_window)
+    {
+      /* Realize so we have the proper width and height to figure out
+       * the right place to popup the menu.
+       */
+      gtk_widget_realize (priv->toplevel);
+
+      if (!gtk_widget_get_visible (priv->toplevel))
+        gtk_window_set_type_hint (GTK_WINDOW (priv->toplevel), priv->menu_type_hint);
+
+      if (text_direction == GTK_TEXT_DIR_NONE)
+        text_direction = gtk_widget_get_direction (GTK_WIDGET (menu));
+
+      if (text_direction == GTK_TEXT_DIR_RTL)
+        {
+          rect_anchor = get_horizontally_flipped_anchor (priv->rect_anchor);
+          menu_anchor = get_horizontally_flipped_anchor (priv->menu_anchor);
+        }
+      else
+        {
+          rect_anchor = priv->rect_anchor;
+          menu_anchor = priv->menu_anchor;
+        }
+
+      toplevel = gtk_widget_get_window (priv->toplevel);
+
+      g_signal_handlers_disconnect_by_func (toplevel, moved_to_rect_cb, menu);
+      g_signal_connect (toplevel, "moved-to-rect", G_CALLBACK (moved_to_rect_cb), menu);
+
+      GDK_PRIVATE_CALL (gdk_window_move_to_rect) (toplevel,
+                                                  rect_window,
+                                                  &rect,
+                                                  rect_anchor,
+                                                  menu_anchor,
+                                                  priv->anchor_hints,
+                                                  priv->rect_anchor_dx,
+                                                  priv->rect_anchor_dy);
+    }
+  else
+    gtk_menu_position_legacy (menu, set_scroll_offset);
+}
+
 static void
 gtk_menu_remove_scroll_timeout (GtkMenu *menu)
 {


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