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



commit 7ad2db28dfb9cd7c4f415406fc13b4a00c8e03df
Author: William Hua <william hua canonical com>
Date:   Wed Jun 15 11:02:52 2016 -0400

    gtkmenu: position menu using gdk_window_move_to_rect ()

 gtk/gtkmarshalers.list |    1 +
 gtk/gtkmenu.c          |  124 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 121 insertions(+), 4 deletions(-)
---
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index c6f12a3..32c0ded 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -106,6 +106,7 @@ VOID:POINTER
 VOID:POINTER,INT
 VOID:POINTER,BOOLEAN
 VOID:POINTER,POINTER,BOOLEAN
+VOID:POINTER,POINTER,BOOLEAN,BOOLEAN
 VOID:POINTER,POINTER,POINTER
 VOID:POINTER,UINT
 VOID:STRING
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 44fff75..0bcadc1 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
@@ -183,6 +184,7 @@ typedef struct
 
 enum {
   MOVE_SCROLL,
+  POPPED_UP,
   LAST_SIGNAL
 };
 
@@ -565,6 +567,21 @@ gtk_menu_class_init (GtkMenuClass *class)
                                 G_TYPE_NONE, 1,
                                 GTK_TYPE_SCROLL_TYPE);
 
+  menu_signals[POPPED_UP] =
+    g_signal_new_class_handler (I_("popped-up"),
+                                G_OBJECT_CLASS_TYPE (gobject_class),
+                                G_SIGNAL_RUN_FIRST,
+                                NULL,
+                                NULL,
+                                NULL,
+                                _gtk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
+                                G_TYPE_NONE,
+                                4,
+                                G_TYPE_POINTER,
+                                G_TYPE_POINTER,
+                                G_TYPE_BOOLEAN,
+                                G_TYPE_BOOLEAN);
+
   /**
    * GtkMenu:active:
    *
@@ -4605,11 +4622,58 @@ gtk_menu_deactivate (GtkMenuShell *menu_shell)
     gtk_menu_shell_deactivate (GTK_MENU_SHELL (parent));
 }
 
+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;
+    default:
+      g_warning ("unknown GdkGravity: %d", anchor);
+      return anchor;
+    }
+}
+
+static void
+moved_to_rect_cb (GdkWindow          *window,
+                  const GdkRectangle *flipped_rect,
+                  const GdkRectangle *slid_rect,
+                  gboolean            flipped_x,
+                  gboolean            flipped_y,
+                  GtkMenu            *menu)
+{
+  g_signal_emit (menu, menu_signals[POPPED_UP], 0, flipped_rect, slid_rect, flipped_x, flipped_y);
+}
+
 static void
 gtk_menu_position (GtkMenu  *menu,
                    gboolean  set_scroll_offset)
 {
   GtkMenuPrivate *priv = menu->priv;
+  GdkWindow *transient_for = NULL;
+  GdkRectangle rect;
+  GtkTextDirection text_direction = GTK_TEXT_DIR_NONE;
+  GdkGravity rect_anchor;
+  GdkGravity menu_anchor;
+  GdkWindow *toplevel;
   GtkWidget *widget;
   GtkRequisition requisition;
   gint x, y;
@@ -4624,15 +4688,67 @@ gtk_menu_position (GtkMenu  *menu,
 
   widget = GTK_WIDGET (menu);
 
-  display = gtk_widget_get_display (widget);
-  pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (menu));
-  gdk_device_get_position (pointer, NULL, &x, &y);
-
   /* 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 (priv->transient_for)
+    {
+      transient_for = priv->transient_for;
+      rect = priv->rect;
+    }
+  else if (priv->widget)
+    {
+      if (gtk_widget_get_parent (priv->widget))
+        transient_for = gtk_widget_get_window (gtk_widget_get_parent (priv->widget));
+      else
+        transient_for = gtk_widget_get_window (priv->widget);
+
+      gtk_widget_get_allocation (priv->widget, &rect);
+      text_direction = gtk_widget_get_direction (priv->widget);
+    }
+
+  if (transient_for)
+    {
+      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 (widget);
+
+      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,
+                                                  transient_for,
+                                                  &rect,
+                                                  rect_anchor,
+                                                  menu_anchor,
+                                                  priv->anchor_hints,
+                                                  priv->rect_anchor_dx,
+                                                  priv->rect_anchor_dy);
+
+      return;
+    }
+
+  display = gtk_widget_get_display (widget);
+  pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (menu));
+  gdk_device_get_position (pointer, NULL, &x, &y);
+
   _gtk_window_get_shadow_width (GTK_WINDOW (priv->toplevel), &border);
 
   requisition.width = gtk_widget_get_allocated_width (widget);


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