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



commit 0698281257a9a5be89144ec73b8b1bf7559e222f
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 |  125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 122 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 391ab87..238c27e 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
@@ -1362,6 +1363,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);
@@ -1388,7 +1406,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);
@@ -4822,8 +4843,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;
@@ -5061,6 +5082,104 @@ 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)
+    {
+      gtk_menu_position_legacy (menu, set_scroll_offset);
+      return;
+    }
+
+  /* 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);
+
+  gdk_window_set_transient_for (toplevel, rect_window);
+
+  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,
+                                              rect_anchor,
+                                              menu_anchor,
+                                              priv->anchor_hints,
+                                              priv->rect_anchor_dx,
+                                              priv->rect_anchor_dy);
+}
+
 static void
 gtk_menu_remove_scroll_timeout (GtkMenu *menu)
 {


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