[gtk+/wip/attach-params: 20/20] gtkcombobox: use gtk_menu_popup_with_params ()



commit d8a9b593fe3a0d1a04fd81df965af346555bdf98
Author: William Hua <william hua canonical com>
Date:   Wed Jan 6 12:00:00 2016 -0500

    gtkcombobox: use gtk_menu_popup_with_params ()
    
    https://bugzilla.gnome.org/show_bug.cgi?id=756579

 gtk/gtkcombobox.c |  306 ++++++++++++++++++----------------------------------
 1 files changed, 106 insertions(+), 200 deletions(-)
---
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index df7f52e..d738104 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -287,21 +287,6 @@ static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
 
 static void     gtk_combo_box_set_popup_widget     (GtkComboBox      *combo_box,
                                                     GtkWidget        *popup);
-static void     gtk_combo_box_menu_position_below  (GtkMenu          *menu,
-                                                    gint             *x,
-                                                    gint             *y,
-                                                    gint             *push_in,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_position_over   (GtkMenu          *menu,
-                                                    gint             *x,
-                                                    gint             *y,
-                                                    gint             *push_in,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_position        (GtkMenu          *menu,
-                                                    gint             *x,
-                                                    gint             *y,
-                                                    gint             *push_in,
-                                                    gpointer          user_data);
 
 static void     gtk_combo_box_unset_model          (GtkComboBox      *combo_box);
 
@@ -1984,185 +1969,6 @@ gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
 }
 
 static void
-gtk_combo_box_menu_position_below (GtkMenu  *menu,
-                                   gint     *x,
-                                   gint     *y,
-                                   gint     *push_in,
-                                   gpointer  user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  GtkComboBoxPrivate *priv = combo_box->priv;
-  GtkAllocation child_allocation, border_allocation, content_allocation;
-  gint sx, sy;
-  GtkWidget *child;
-  GtkRequisition req;
-  GdkScreen *screen;
-  gint monitor_num;
-  GdkRectangle monitor;
-
-  /* FIXME: is using the size request here broken? */
-  child = gtk_bin_get_child (GTK_BIN (combo_box));
-
-  sx = sy = 0;
-
-  gtk_css_gadget_get_border_allocation (priv->gadget, &border_allocation, NULL);
-  gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
-  gtk_widget_get_allocation (child, &child_allocation);
-
-  if (!gtk_widget_get_has_window (child))
-    {
-      sx += child_allocation.x;
-      sy += child_allocation.y;
-    }
-
-  gdk_window_get_root_coords (gtk_widget_get_window (child),
-                              sx, sy, &sx, &sy);
-
-  if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL)
-    sx += (content_allocation.x - border_allocation.x);
-  else
-    sx -= (content_allocation.x - border_allocation.x);
-
-  if (combo_box->priv->popup_fixed_width)
-    gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
-  else
-    gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
-
-  if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR)
-    *x = sx;
-  else
-    *x = sx + child_allocation.width - req.width;
-  *y = sy;
-
-  screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
-  monitor_num = gdk_screen_get_monitor_at_window (screen,
-                                                  gtk_widget_get_window (GTK_WIDGET (combo_box)));
-  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
-
-  if (*x < monitor.x)
-    *x = monitor.x;
-  else if (*x + req.width > monitor.x + monitor.width)
-    *x = monitor.x + monitor.width - req.width;
-
-  if (monitor.y + monitor.height - *y - child_allocation.height >= req.height)
-    *y += child_allocation.height;
-  else if (*y - monitor.y >= req.height)
-    *y -= req.height;
-  else if (monitor.y + monitor.height - *y - child_allocation.height > *y - monitor.y)
-    *y += child_allocation.height;
-  else
-    *y -= req.height;
-
-   *push_in = FALSE;
-}
-
-static void
-gtk_combo_box_menu_position_over (GtkMenu  *menu,
-                                  gint     *x,
-                                  gint     *y,
-                                  gboolean *push_in,
-                                  gpointer  user_data)
-{
-  GtkComboBox        *combo_box = GTK_COMBO_BOX (user_data);
-  GtkWidget          *widget    = GTK_WIDGET (combo_box);
-  GtkComboBoxPrivate *priv      = combo_box->priv;
-  GtkWidget          *active;
-  GtkWidget          *child;
-  GtkAllocation       content_allocation;
-  GtkAllocation       child_allocation;
-  GList              *children;
-  gint                screen_width;
-  gint                menu_xpos;
-  gint                menu_ypos;
-  gint                menu_width;
-
-  active = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
-
-  gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
-
-  menu_xpos = content_allocation.x;
-  menu_ypos = content_allocation.y + content_allocation.height / 2 - 2;
-
-  if (priv->popup_fixed_width)
-    gtk_widget_get_preferred_width (GTK_WIDGET (menu), &menu_width, NULL);
-  else
-    gtk_widget_get_preferred_width (GTK_WIDGET (menu), NULL, &menu_width);
-
-  if (active != NULL)
-    {
-      gtk_widget_get_allocation (active, &child_allocation);
-      menu_ypos -= child_allocation.height / 2;
-    }
-
-  children = GTK_MENU_SHELL (priv->popup_widget)->priv->children;
-  while (children)
-    {
-      child = children->data;
-
-      if (active == child)
-        break;
-
-      if (gtk_widget_get_visible (child))
-        {
-          gtk_widget_get_allocation (child, &child_allocation);
-
-          menu_ypos -= child_allocation.height;
-        }
-
-      children = children->next;
-    }
-
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
-    menu_xpos = menu_xpos + content_allocation.width - menu_width;
-
-  gdk_window_get_root_coords (gtk_widget_get_window (widget),
-                              menu_xpos, menu_ypos,
-                              &menu_xpos, &menu_ypos);
-
-  /* Clamp the position on screen */
-  screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));
-  
-  if (menu_xpos < 0)
-    menu_xpos = 0;
-  else if ((menu_xpos + menu_width) > screen_width)
-    menu_xpos -= ((menu_xpos + menu_width) - screen_width);
-
-  *x = menu_xpos;
-  *y = menu_ypos;
-
-  *push_in = TRUE;
-}
-
-static void
-gtk_combo_box_menu_position (GtkMenu  *menu,
-                             gint     *x,
-                             gint     *y,
-                             gint     *push_in,
-                             gpointer  user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  GtkComboBoxPrivate *priv = combo_box->priv;
-  GtkWidget *menu_item;
-
-  if (priv->wrap_width > 0 || priv->cell_view == NULL)
-    gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data);
-  else
-    {
-      /* FIXME handle nested menus better */
-      menu_item = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
-      if (menu_item)
-        gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->popup_widget),
-                                    menu_item);
-
-      gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
-    }
-
-  if (!gtk_widget_get_visible (GTK_MENU (priv->popup_widget)->priv->toplevel))
-    gtk_window_set_type_hint (GTK_WINDOW (GTK_MENU (priv->popup_widget)->priv->toplevel),
-                              GDK_WINDOW_TYPE_HINT_COMBO);
-}
-
-static void
 gtk_combo_box_list_position (GtkComboBox *combo_box,
                              gint        *x,
                              gint        *y,
@@ -2369,6 +2175,15 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
   GtkTreePath *path;
   gint active_item;
   gint width, min_width, nat_width;
+  GdkAttachParams *params;
+  gint offset_y = 0;
+  GtkWidget *attach_widget;
+  GtkWidget *active_widget;
+  GtkAllocation border_allocation;
+  GtkAllocation content_allocation;
+  GdkBorder margin;
+  gint height;
+  GList *i;
 
   update_menu_sensitivity (combo_box, priv->popup_widget);
 
@@ -2388,8 +2203,6 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
 
   if (priv->wrap_width == 0)
     {
-      GtkAllocation content_allocation;
-
       gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
       width = content_allocation.width;
       gtk_widget_set_size_request (priv->popup_widget, -1, -1);
@@ -2403,10 +2216,103 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
       gtk_widget_set_size_request (priv->popup_widget, width, -1);
     }
 
-  gtk_menu_popup (GTK_MENU (priv->popup_widget),
-                  NULL, NULL,
-                  gtk_combo_box_menu_position, combo_box,
-                  button, activate_time);
+  params = gtk_menu_create_params (GTK_MENU (priv->popup_widget));
+
+  if (priv->wrap_width > 0 || !priv->cell_view)
+    {
+      attach_widget = gtk_bin_get_child (GTK_BIN (combo_box));
+
+      gtk_css_gadget_get_border_allocation (priv->gadget, &border_allocation, NULL);
+      gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
+
+      margin.top = content_allocation.y - border_allocation.y;
+      margin.left = content_allocation.x - border_allocation.x;
+      margin.right = content_allocation.x - border_allocation.x;
+      margin.bottom = content_allocation.y - border_allocation.y;
+
+      gdk_attach_params_set_attach_margin (params, &margin);
+
+      gdk_attach_params_add_primary_rules (params,
+                                           GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MIN,
+                                           GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MAX,
+                                           NULL);
+
+      gdk_attach_params_add_secondary_rules (params,
+                                             GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MIN,
+                                             GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MAX,
+                                             NULL);
+
+      gdk_attach_params_set_position_callback (params,
+                                               gtk_menu_update_scroll_offset,
+                                               g_object_ref (priv->popup_widget),
+                                               g_object_unref);
+
+      gtk_menu_popup_with_params (GTK_MENU (priv->popup_widget),
+                                  NULL,
+                                  NULL,
+                                  attach_widget,
+                                  button,
+                                  activate_time,
+                                  TRUE,
+                                  GDK_WINDOW_TYPE_HINT_COMBO,
+                                  params);
+    }
+  else
+    {
+      attach_widget = GTK_WIDGET (combo_box);
+      active_widget = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
+      i = GTK_MENU_SHELL (priv->popup_widget)->priv->children;
+
+      gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
+
+      if (active_widget)
+        gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->popup_widget), active_widget);
+      else if (i)
+        active_widget = i->data;
+
+      for (; i && i->data != active_widget; i = i->next)
+        {
+          if (gtk_widget_get_visible (i->data))
+            {
+              gtk_widget_get_preferred_height (i->data, &height, NULL);
+              offset_y -= height;
+            }
+        }
+
+      if (i && gtk_widget_get_visible (active_widget))
+        {
+          gtk_widget_get_preferred_height (active_widget, &height, NULL);
+          offset_y -= height / 2;
+        }
+
+      gdk_attach_params_set_attach_rect (params, &content_allocation, gtk_widget_get_window (attach_widget));
+
+      gdk_attach_params_set_window_offset (params, 0, offset_y);
+
+      gdk_attach_params_add_primary_rules (params,
+                                           GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MID | GDK_ATTACH_WINDOW_MIN,
+                                           NULL);
+
+      gdk_attach_params_add_secondary_rules (params,
+                                             GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MIN,
+                                             GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MAX,
+                                             NULL);
+
+      gdk_attach_params_set_position_callback (params,
+                                               gtk_menu_update_scroll_offset,
+                                               g_object_ref (priv->popup_widget),
+                                               g_object_unref);
+
+      gtk_menu_popup_with_params (GTK_MENU (priv->popup_widget),
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  button,
+                                  activate_time,
+                                  TRUE,
+                                  GDK_WINDOW_TYPE_HINT_COMBO,
+                                  params);
+    }
 }
 
 static gboolean


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