[gtk+/combo-refactor: 28/42] Fixing up the combo box gtktreemodel listener signals.



commit 5503592e4a1257eadf2633f59fee1089daff5450
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Thu Nov 25 14:41:40 2010 +0900

    Fixing up the combo box gtktreemodel listener signals.

 gtk/gtkcombobox.c | 1186 ++++++++++++++++++++++++++---------------------------
 1 files changed, 592 insertions(+), 594 deletions(-)
---
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index 0090308..3c55e7c 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -197,6 +197,16 @@ static void     gtk_combo_box_real_move_active     (GtkComboBox      *combo_box,
 static void     gtk_combo_box_real_popup           (GtkComboBox      *combo_box);
 static gboolean gtk_combo_box_real_popdown         (GtkComboBox      *combo_box);
 
+
+/* GtkTreeModel signals */
+static void     gtk_combo_box_model_row_inserted   (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    GtkTreeIter      *iter,
+						    gpointer          user_data);
+static void     gtk_combo_box_model_row_deleted    (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    gpointer          user_data);
+
 static void     gtk_combo_box_menu_show            (GtkWidget        *menu,
                                                     gpointer          user_data);
 static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
@@ -204,21 +214,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);
 static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
@@ -289,6 +284,22 @@ static void     gtk_combo_box_menu_popup           (GtkComboBox      *combo_box,
 						    guint             button, 
 						    guint32           activate_time);
 
+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 gboolean gtk_combo_box_mnemonic_activate              (GtkWidget    *widget,
 							      gboolean      group_cycling);
 
@@ -364,8 +375,6 @@ struct _GtkComboBoxPrivate
 
   gulong     inserted_id;
   gulong     deleted_id;
-  gulong     reordered_id;
-  gulong     changed_id;
   guint      popup_idle_id;
   guint      activate_button;
   guint32    activate_time;
@@ -1711,6 +1720,519 @@ gtk_combo_box_destroy (GtkWidget *widget)
   combo_box->priv->cell_view = NULL;
 }
 
+
+static void     
+gtk_combo_box_get_preferred_width (GtkWidget *widget,
+                                   gint      *minimum_size,
+                                   gint      *natural_size)
+{
+  GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
+  GtkComboBoxPrivate    *priv = combo_box->priv;
+  GtkStyle              *style;
+  gint                   focus_width, focus_pad;
+  gint                   font_size, arrow_size;
+  PangoContext          *context;
+  PangoFontMetrics      *metrics;
+  PangoFontDescription  *font_desc;
+  GtkWidget             *child;
+  gint                   minimum_width, natural_width;
+  gint                   child_min, child_nat;
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+ 
+  /* common */
+  gtk_widget_get_preferred_width (child, &child_min, &child_nat);
+
+  gtk_widget_style_get (GTK_WIDGET (widget),
+			"focus-line-width", &focus_width,
+			"focus-padding", &focus_pad,
+			"arrow-size", &arrow_size,
+			NULL);
+
+  font_desc = gtk_widget_get_style (child)->font_desc;
+  context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
+  metrics = pango_context_get_metrics (context, font_desc,
+				       pango_context_get_language (context));
+  font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
+			    pango_font_metrics_get_descent (metrics));
+  pango_font_metrics_unref (metrics);
+
+  arrow_size = MAX (arrow_size, font_size);
+
+  gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
+
+  if (!priv->tree_view)
+    {
+      /* menu mode */	  
+      if (priv->cell_view)
+        {
+          gint sep_width, arrow_width;
+          gint border_width, xthickness, xpad;
+
+	  border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
+          xthickness   = gtk_widget_get_style (priv->button)->xthickness;
+
+          gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
+          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
+
+	  xpad = 2*(border_width + xthickness + focus_width + focus_pad);
+
+          minimum_width  = child_min + sep_width + arrow_width + xpad;
+          natural_width  = child_nat + sep_width + arrow_width + xpad;
+        }
+      else
+        {
+          gint but_width, but_nat_width;
+
+          gtk_widget_get_preferred_width (priv->button, 
+                                          &but_width, &but_nat_width);
+
+          minimum_width  = child_min + but_width;
+          natural_width  = child_nat + but_nat_width;
+        }
+    }
+  else
+    {
+      /* list mode */
+      gint button_width, button_nat_width;
+
+      /* sample + frame */
+      minimum_width = child_min;
+      natural_width = child_nat;
+
+      minimum_width += 2 * focus_width;
+      natural_width += 2 * focus_width;
+      
+      if (priv->cell_view_frame)
+        {
+	  if (priv->has_frame)
+	    {
+	      gint border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
+	      gint xpad         = 2 * (border_width + gtk_widget_get_style (GTK_WIDGET (priv->cell_view_frame))->xthickness);
+
+	      minimum_width  += xpad;
+	      natural_width  += xpad;
+	    }
+        }
+
+      /* the button */
+      gtk_widget_get_preferred_width (priv->button, 
+                                      &button_width, &button_nat_width);
+
+      minimum_width += button_width;
+      natural_width += button_nat_width;
+    }
+
+  if (GTK_SHADOW_NONE != priv->shadow_type)
+    {
+      style = gtk_widget_get_style (GTK_WIDGET (widget));
+
+      minimum_width  += 2 * style->xthickness;
+      natural_width  += 2 * style->xthickness;
+    }
+
+  if (minimum_size)
+    *minimum_size = minimum_width;
+
+  if (natural_size)
+    *natural_size = natural_width;
+}
+
+static void
+gtk_combo_box_get_preferred_height (GtkWidget *widget,
+                                    gint      *minimum_size,
+                                    gint      *natural_size)
+{ 
+  gint min_width;
+
+  /* Combo box is height-for-width only 
+   * (so we always just reserve enough height for the minimum width) */
+  GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
+  GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width, minimum_size, natural_size);
+}
+
+static void
+gtk_combo_box_get_preferred_width_for_height (GtkWidget *widget,
+                                              gint       avail_size,
+                                              gint      *minimum_size,
+                                              gint      *natural_size)
+{
+  /* Combo box is height-for-width only 
+   * (so we assume we always reserved enough height for the minimum width) */
+  GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_size, natural_size);
+}
+
+
+static void
+gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
+                                              gint       avail_size,
+                                              gint      *minimum_size,
+                                              gint      *natural_size)
+{
+  GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
+  GtkComboBoxPrivate    *priv = combo_box->priv;
+  GtkStyle              *style;
+  gint                   focus_width, focus_pad;
+  gint                   min_height, nat_height;
+  gint                   size;
+  GtkWidget             *child;
+
+  gtk_widget_style_get (GTK_WIDGET (widget),
+			"focus-line-width", &focus_width,
+			"focus-padding", &focus_pad,
+			NULL);
+
+  size = avail_size;
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+
+  if (GTK_SHADOW_NONE != priv->shadow_type)
+    size -= gtk_widget_get_style (GTK_WIDGET (widget))->xthickness;
+
+  if (!priv->tree_view)
+    {
+      /* menu mode */
+      if (priv->cell_view)
+        {
+          GtkStyle *button_style;
+	  /* calculate x/y padding and separator/arrow size */
+          gint sep_width, arrow_width, sep_height, arrow_height;
+          gint border_width, xthickness, ythickness, xpad, ypad;
+
+	  border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
+          button_style = gtk_widget_get_style (priv->button);
+
+          xthickness = button_style->xthickness;
+          ythickness = button_style->ythickness;
+
+          gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
+          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
+          gtk_widget_get_preferred_height_for_width (priv->separator, 
+                                                     sep_width, &sep_height, NULL);
+          gtk_widget_get_preferred_height_for_width (priv->arrow, 
+                                                     arrow_width, &arrow_height, NULL);
+
+	  xpad = 2*(border_width + xthickness + focus_width + focus_pad);
+	  ypad = 2*(border_width + ythickness + focus_width + focus_pad);
+
+	  size -= sep_width + arrow_width + xpad;
+
+	  /* Get height-for-width of the child widget, usually a GtkCellArea calculating
+	   * and fitting the whole treemodel */
+	  gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
+
+	  arrow_height = MAX (arrow_height, sep_height);
+	  min_height = MAX (min_height, arrow_height);
+	  nat_height = MAX (nat_height, arrow_height);
+
+	  min_height += ypad;
+	  nat_height += ypad;
+        }
+      else
+        {
+	  /* there is a custom child widget inside (no priv->cell_view) */
+          gint but_width, but_height;
+
+          gtk_widget_get_preferred_width (priv->button, &but_width, NULL);
+          gtk_widget_get_preferred_height_for_width (priv->button, 
+                                                     but_width, &but_height, NULL);
+
+	  size -= but_width;
+
+	  /* Get height-for-width of the child widget, usually a GtkCellArea calculating
+	   * and fitting the whole treemodel */
+	  gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
+	  
+	  min_height = MAX (min_height, but_height);
+	  nat_height = MAX (nat_height, but_height);
+        }
+    }
+  else
+    {
+      /* list mode */
+      gint but_width, but_height;
+      gint xpad = 0, ypad = 0;
+
+      gtk_widget_get_preferred_width (priv->button, &but_width, NULL);
+      gtk_widget_get_preferred_height_for_width (priv->button, 
+                                                 but_width, &but_height, NULL);
+      
+      if (priv->cell_view_frame && priv->has_frame)
+	{
+          GtkStyle *cell_style;
+	  gint border_width;
+
+          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
+          cell_style = gtk_widget_get_style (GTK_WIDGET (priv->cell_view_frame));
+
+	  xpad = 2 * (border_width + cell_style->xthickness);
+	  ypad = 2 * (border_width + cell_style->ythickness);
+	}
+
+      size -= but_width;
+      size -= 2 * focus_width;
+      size -= xpad;
+ 
+      /* Get height-for-width of the child widget, usually a GtkCellArea calculating
+       * and fitting the whole treemodel */
+      gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
+
+      min_height = MAX (min_height, but_height);
+      nat_height = MAX (nat_height, but_height);
+
+      min_height += ypad;
+      nat_height += ypad;
+    }
+
+  if (GTK_SHADOW_NONE != priv->shadow_type)
+    {
+      style = gtk_widget_get_style (GTK_WIDGET (widget));
+
+      min_height += 2 * style->ythickness;
+      nat_height += 2 * style->ythickness;
+    }
+
+  if (minimum_size)
+    *minimum_size = min_height;
+
+  if (natural_size)
+    *natural_size = nat_height;
+}
+
+#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON 					\
+  gtk_widget_get_preferred_size (combo_box->priv->button,	                \
+                                 &req, NULL); 					\
+  										\
+  if (is_rtl) 									\
+    child.x = allocation->x + shadow_width;					\
+  else										\
+    child.x = allocation->x + allocation->width - req.width - shadow_width;	\
+    										\
+  child.y = allocation->y + shadow_height;					\
+  child.width = req.width;							\
+  child.height = allocation->height - 2 * shadow_height;			\
+  child.width = MAX (1, child.width);						\
+  child.height = MAX (1, child.height);						\
+  										\
+  gtk_widget_size_allocate (combo_box->priv->button, &child);
+
+static void
+gtk_combo_box_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+  GtkComboBoxPrivate *priv = combo_box->priv;
+  GtkWidget *child_widget;
+  gint shadow_width, shadow_height;
+  gint focus_width, focus_pad;
+  GtkAllocation child;
+  GtkRequisition req;
+  GtkStyle *style;
+  gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+  gtk_widget_set_allocation (widget, allocation);
+  child_widget = gtk_bin_get_child (GTK_BIN (widget));
+
+  style = gtk_widget_get_style (widget);
+  gtk_widget_style_get (widget,
+			"focus-line-width", &focus_width,
+			"focus-padding", &focus_pad,
+			NULL);
+
+  if (GTK_SHADOW_NONE != priv->shadow_type)
+    {
+      shadow_width = style->xthickness;
+      shadow_height = style->ythickness;
+    }
+  else
+    {
+      shadow_width = 0;
+      shadow_height = 0;
+    }
+
+  if (!priv->tree_view)
+    {
+      if (priv->cell_view)
+        {
+          gint xthickness, ythickness;
+          gint width;
+          guint border_width;
+
+          /* menu mode */
+          allocation->x += shadow_width;
+          allocation->y += shadow_height;
+          allocation->width -= 2 * shadow_width;
+          allocation->height -= 2 * shadow_height;
+
+          gtk_widget_size_allocate (priv->button, allocation);
+
+          /* set some things ready */
+          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button));
+          style = gtk_widget_get_style (priv->button);
+          xthickness = style->xthickness;
+          ythickness = style->ythickness;
+
+          child.x = allocation->x;
+          child.y = allocation->y;
+	  width = allocation->width;
+	  child.height = allocation->height;
+
+	  if (!priv->is_cell_renderer)
+	    {
+	      child.x += border_width + xthickness + focus_width + focus_pad;
+	      child.y += border_width + ythickness + focus_width + focus_pad;
+	      width -= 2 * (child.x - allocation->x);
+	      child.height -= 2 * (child.y - allocation->y);
+	    }
+
+
+          /* handle the children */
+          gtk_widget_get_preferred_size (priv->arrow, &req, NULL);
+          child.width = req.width;
+          if (!is_rtl)
+            child.x += width - req.width;
+	  child.width = MAX (1, child.width);
+	  child.height = MAX (1, child.height);
+          gtk_widget_size_allocate (priv->arrow, &child);
+          if (is_rtl)
+            child.x += req.width;
+          gtk_widget_get_preferred_size (priv->separator, &req, NULL);
+          child.width = req.width;
+          if (!is_rtl)
+            child.x -= req.width;
+	  child.width = MAX (1, child.width);
+	  child.height = MAX (1, child.height);
+          gtk_widget_size_allocate (priv->separator, &child);
+
+          if (is_rtl)
+            {
+              child.x += req.width;
+              child.width = allocation->x + allocation->width 
+                - (border_width + xthickness + focus_width + focus_pad) 
+		- child.x;
+            }
+          else 
+            {
+              child.width = child.x;
+              child.x = allocation->x 
+		+ border_width + xthickness + focus_width + focus_pad;
+              child.width -= child.x;
+            }
+
+          if (gtk_widget_get_visible (priv->popup_widget))
+            {
+              gint width, menu_width;
+
+              if (priv->wrap_width == 0)
+                {
+                  GtkAllocation combo_box_allocation;
+
+                  gtk_widget_get_allocation (GTK_WIDGET (combo_box), &combo_box_allocation);
+                  width = combo_box_allocation.width;
+                  gtk_widget_set_size_request (priv->popup_widget, -1, -1);
+
+		  if (combo_box->priv->popup_fixed_width)
+		    gtk_widget_get_preferred_width (priv->popup_widget, &menu_width, NULL);
+		  else
+		    gtk_widget_get_preferred_width (priv->popup_widget, NULL, &menu_width);
+
+                  gtk_widget_set_size_request (priv->popup_widget,
+					       MAX (width, menu_width), -1);
+               }
+
+              /* reposition the menu after giving it a new width */
+              gtk_menu_reposition (GTK_MENU (priv->popup_widget));
+            }
+
+	  child.width = MAX (1, child.width);
+	  child.height = MAX (1, child.height);
+          gtk_widget_size_allocate (child_widget, &child);
+        }
+      else
+        {
+          GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
+
+          if (is_rtl)
+            child.x = allocation->x + req.width + shadow_width;
+          else
+            child.x = allocation->x + shadow_width;
+          child.y = allocation->y + shadow_height;
+          child.width = allocation->width - req.width - 2 * shadow_width;
+	  child.width = MAX (1, child.width);
+	  child.height = MAX (1, child.height);
+          gtk_widget_size_allocate (child_widget, &child);
+        }
+    }
+  else
+    {
+      /* list mode */
+
+      /* Combobox thickness + border-width */
+      guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+      int delta_x = shadow_width + border_width;
+      int delta_y = shadow_height + border_width;
+
+      /* button */
+      GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
+
+      /* frame */
+      if (is_rtl)
+        child.x = allocation->x + req.width;
+      else
+        child.x = allocation->x;
+
+      child.y = allocation->y;
+      child.width = allocation->width - req.width;
+      child.height = allocation->height;
+
+      if (priv->cell_view_frame)
+        {
+          child.x += delta_x;
+          child.y += delta_y;
+          child.width = MAX (1, child.width - delta_x * 2);
+          child.height = MAX (1, child.height - delta_y * 2);
+          gtk_widget_size_allocate (priv->cell_view_frame, &child);
+
+          /* the sample */
+          if (priv->has_frame)
+            {
+              border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
+              style = gtk_widget_get_style (priv->cell_view_frame);
+              delta_x = border_width + style->xthickness;
+              delta_y = border_width + style->ythickness;
+
+              child.x += delta_x;
+              child.y += delta_y;
+              child.width -= delta_x * 2;
+              child.height -= delta_y * 2;
+            }
+        }
+      else
+        {
+          child.x += delta_x;
+          child.y += delta_y;
+          child.width -= delta_x * 2;
+          child.height -= delta_y * 2;
+        }
+
+      if (gtk_widget_get_visible (priv->popup_window))
+        {
+          gint x, y, width, height;
+          gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
+          gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
+          gtk_widget_set_size_request (priv->popup_window, width, height);
+        }
+
+      
+      child.width = MAX (1, child.width);
+      child.height = MAX (1, child.height);
+      
+      gtk_widget_size_allocate (child_widget, &child);
+    }
+}
+
+#undef GTK_COMBO_BOX_ALLOCATE_BUTTON
+
 /******************************************************
  *                  GtkContainerClass                 *
  ******************************************************/
@@ -1998,6 +2520,40 @@ gtk_combo_box_real_popdown (GtkComboBox *combo_box)
 }
 
 
+/******************************************************
+ *                 GtkTreeModel callbacks             *
+ ******************************************************/
+static void
+gtk_combo_box_model_row_inserted (GtkTreeModel     *model,
+				  GtkTreePath      *path,
+				  GtkTreeIter      *iter,
+				  gpointer          user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  if (combo_box->priv->tree_view)
+    gtk_combo_box_list_popup_resize (combo_box);
+}
+
+static void
+gtk_combo_box_model_row_deleted (GtkTreeModel     *model,
+				 GtkTreePath      *path,
+				 gpointer          user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+  GtkComboBoxPrivate *priv = combo_box->priv;
+
+  if (!gtk_tree_row_reference_valid (priv->active_row))
+    {
+      if (priv->cell_view)
+	gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv->cell_view), NULL);
+      g_signal_emit (combo_box, combo_box_signals[CHANGED], 0);
+    }
+  
+  if (priv->tree_view)
+    gtk_combo_box_list_popup_resize (combo_box);
+}
+
 
 static void
 gtk_combo_box_button_toggled (GtkWidget *widget,
@@ -2375,10 +2931,6 @@ gtk_combo_box_list_position (GtkComboBox *combo_box,
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
 				  hpolicy, vpolicy);
 
-  /* XXX This set_size_request call is part of the hack outlined below and can 
-   * go away once height-for-width is implemented on treeviews. */
-  gtk_widget_set_size_request (priv->tree_view, -1, -1);
-
   if (combo_box->priv->popup_fixed_width)
     {
       gtk_widget_get_preferred_size (priv->scrolled_window, &popup_req, NULL);
@@ -2392,26 +2944,15 @@ gtk_combo_box_list_position (GtkComboBox *combo_box,
     }
   else
     {
-      /* XXX Here we need the GtkCellAreaContext shared with the treemenu/treeviewcolumn */
-      if (1/* XXX */ > *width)
+      /* This code depends on treeviews properly reporting their natural width */
+      gtk_widget_get_preferred_size (priv->scrolled_window, NULL, &popup_req);
+
+      if (popup_req.width > *width)
 	{
 	  hpolicy = GTK_POLICY_NEVER;
 	  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
 					  hpolicy, vpolicy);
 
-
-	  /* XXX Currently we set the size-request on the internal treeview to be
-	   * the natural width of the cells, this hack can go away once our
-	   * treeview does height-for-width properly (i.e. just adjust *width
-	   * here to be the natural width request of the scrolled-window). 
-	   *
-	   * I can't tell why the magic number 5 is needed here (i.e. without it 
-	   * treeviews are left ellipsizing) , however it this all should be
-	   * removed with height-for-width treeviews.
-	   */
-	  gtk_widget_set_size_request (priv->tree_view, 1 /* XXX */ + 5, -1);
-	  gtk_widget_get_preferred_size (priv->scrolled_window, NULL, &popup_req);
-
 	  *width = popup_req.width;
 	}
     }
@@ -2530,518 +3071,6 @@ popup_grab_on_window (GdkWindow *window,
   return TRUE;
 }
 
-static void     
-gtk_combo_box_get_preferred_width (GtkWidget *widget,
-                                   gint      *minimum_size,
-                                   gint      *natural_size)
-{
-  GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
-  GtkComboBoxPrivate    *priv = combo_box->priv;
-  GtkStyle              *style;
-  gint                   focus_width, focus_pad;
-  gint                   font_size, arrow_size;
-  PangoContext          *context;
-  PangoFontMetrics      *metrics;
-  PangoFontDescription  *font_desc;
-  GtkWidget             *child;
-  gint                   minimum_width, natural_width;
-  gint                   child_min, child_nat;
-
-  child = gtk_bin_get_child (GTK_BIN (widget));
- 
-  /* common */
-  gtk_widget_get_preferred_width (child, &child_min, &child_nat);
-
-  gtk_widget_style_get (GTK_WIDGET (widget),
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"arrow-size", &arrow_size,
-			NULL);
-
-  font_desc = gtk_widget_get_style (child)->font_desc;
-  context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
-  metrics = pango_context_get_metrics (context, font_desc,
-				       pango_context_get_language (context));
-  font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
-			    pango_font_metrics_get_descent (metrics));
-  pango_font_metrics_unref (metrics);
-
-  arrow_size = MAX (arrow_size, font_size);
-
-  gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
-
-  if (!priv->tree_view)
-    {
-      /* menu mode */	  
-      if (priv->cell_view)
-        {
-          gint sep_width, arrow_width;
-          gint border_width, xthickness, xpad;
-
-	  border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
-          xthickness   = gtk_widget_get_style (priv->button)->xthickness;
-
-          gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
-          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
-
-	  xpad = 2*(border_width + xthickness + focus_width + focus_pad);
-
-          minimum_width  = child_min + sep_width + arrow_width + xpad;
-          natural_width  = child_nat + sep_width + arrow_width + xpad;
-        }
-      else
-        {
-          gint but_width, but_nat_width;
-
-          gtk_widget_get_preferred_width (priv->button, 
-                                          &but_width, &but_nat_width);
-
-          minimum_width  = child_min + but_width;
-          natural_width  = child_nat + but_nat_width;
-        }
-    }
-  else
-    {
-      /* list mode */
-      gint button_width, button_nat_width;
-
-      /* sample + frame */
-      minimum_width = child_min;
-      natural_width = child_nat;
-
-      minimum_width += 2 * focus_width;
-      natural_width += 2 * focus_width;
-      
-      if (priv->cell_view_frame)
-        {
-	  if (priv->has_frame)
-	    {
-	      gint border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
-	      gint xpad         = 2 * (border_width + gtk_widget_get_style (GTK_WIDGET (priv->cell_view_frame))->xthickness);
-
-	      minimum_width  += xpad;
-	      natural_width  += xpad;
-	    }
-        }
-
-      /* the button */
-      gtk_widget_get_preferred_width (priv->button, 
-                                      &button_width, &button_nat_width);
-
-      minimum_width += button_width;
-      natural_width += button_nat_width;
-    }
-
-  if (GTK_SHADOW_NONE != priv->shadow_type)
-    {
-      style = gtk_widget_get_style (GTK_WIDGET (widget));
-
-      minimum_width  += 2 * style->xthickness;
-      natural_width  += 2 * style->xthickness;
-    }
-
-  if (minimum_size)
-    *minimum_size = minimum_width;
-
-  if (natural_size)
-    *natural_size = natural_width;
-}
-
-static void
-gtk_combo_box_get_preferred_height (GtkWidget *widget,
-                                    gint      *minimum_size,
-                                    gint      *natural_size)
-{ 
-  gint min_width;
-
-  /* Combo box is height-for-width only 
-   * (so we always just reserve enough height for the minimum width) */
-  GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
-  GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width, minimum_size, natural_size);
-}
-
-static void
-gtk_combo_box_get_preferred_width_for_height (GtkWidget *widget,
-                                              gint       avail_size,
-                                              gint      *minimum_size,
-                                              gint      *natural_size)
-{
-  /* Combo box is height-for-width only 
-   * (so we assume we always reserved enough height for the minimum width) */
-  GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_size, natural_size);
-}
-
-
-static void
-gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
-                                              gint       avail_size,
-                                              gint      *minimum_size,
-                                              gint      *natural_size)
-{
-  GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
-  GtkComboBoxPrivate    *priv = combo_box->priv;
-  GtkStyle              *style;
-  gint                   focus_width, focus_pad;
-  gint                   min_height, nat_height;
-  gint                   size;
-  GtkWidget             *child;
-
-  gtk_widget_style_get (GTK_WIDGET (widget),
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			NULL);
-
-  size = avail_size;
-
-  child = gtk_bin_get_child (GTK_BIN (widget));
-
-  if (GTK_SHADOW_NONE != priv->shadow_type)
-    size -= gtk_widget_get_style (GTK_WIDGET (widget))->xthickness;
-
-  if (!priv->tree_view)
-    {
-      /* menu mode */
-      if (priv->cell_view)
-        {
-          GtkStyle *button_style;
-	  /* calculate x/y padding and separator/arrow size */
-          gint sep_width, arrow_width, sep_height, arrow_height;
-          gint border_width, xthickness, ythickness, xpad, ypad;
-
-	  border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
-          button_style = gtk_widget_get_style (priv->button);
-
-          xthickness = button_style->xthickness;
-          ythickness = button_style->ythickness;
-
-          gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL);
-          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->separator, 
-                                                     sep_width, &sep_height, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->arrow, 
-                                                     arrow_width, &arrow_height, NULL);
-
-	  xpad = 2*(border_width + xthickness + focus_width + focus_pad);
-	  ypad = 2*(border_width + ythickness + focus_width + focus_pad);
-
-	  size -= sep_width + arrow_width + xpad;
-
-	  /* Get height-for-width of the child widget, usually a GtkCellArea calculating
-	   * and fitting the whole treemodel */
-	  gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
-
-	  arrow_height = MAX (arrow_height, sep_height);
-	  min_height = MAX (min_height, arrow_height);
-	  nat_height = MAX (nat_height, arrow_height);
-
-	  min_height += ypad;
-	  nat_height += ypad;
-        }
-      else
-        {
-	  /* there is a custom child widget inside (no priv->cell_view) */
-          gint but_width, but_height;
-
-          gtk_widget_get_preferred_width (priv->button, &but_width, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->button, 
-                                                     but_width, &but_height, NULL);
-
-	  size -= but_width;
-
-	  /* Get height-for-width of the child widget, usually a GtkCellArea calculating
-	   * and fitting the whole treemodel */
-	  gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
-	  
-	  min_height = MAX (min_height, but_height);
-	  nat_height = MAX (nat_height, but_height);
-        }
-    }
-  else
-    {
-      /* list mode */
-      gint but_width, but_height;
-      gint xpad = 0, ypad = 0;
-
-      gtk_widget_get_preferred_width (priv->button, &but_width, NULL);
-      gtk_widget_get_preferred_height_for_width (priv->button, 
-                                                 but_width, &but_height, NULL);
-      
-      if (priv->cell_view_frame && priv->has_frame)
-	{
-          GtkStyle *cell_style;
-	  gint border_width;
-
-          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
-          cell_style = gtk_widget_get_style (GTK_WIDGET (priv->cell_view_frame));
-
-	  xpad = 2 * (border_width + cell_style->xthickness);
-	  ypad = 2 * (border_width + cell_style->ythickness);
-	}
-
-      size -= but_width;
-      size -= 2 * focus_width;
-      size -= xpad;
- 
-      /* Get height-for-width of the child widget, usually a GtkCellArea calculating
-       * and fitting the whole treemodel */
-      gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
-
-      min_height = MAX (min_height, but_height);
-      nat_height = MAX (nat_height, but_height);
-
-      min_height += ypad;
-      nat_height += ypad;
-    }
-
-  if (GTK_SHADOW_NONE != priv->shadow_type)
-    {
-      style = gtk_widget_get_style (GTK_WIDGET (widget));
-
-      min_height += 2 * style->ythickness;
-      nat_height += 2 * style->ythickness;
-    }
-
-  if (minimum_size)
-    *minimum_size = min_height;
-
-  if (natural_size)
-    *natural_size = nat_height;
-}
-
-#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON 					\
-  gtk_widget_get_preferred_size (combo_box->priv->button,	                \
-                                 &req, NULL); 					\
-  										\
-  if (is_rtl) 									\
-    child.x = allocation->x + shadow_width;					\
-  else										\
-    child.x = allocation->x + allocation->width - req.width - shadow_width;	\
-    										\
-  child.y = allocation->y + shadow_height;					\
-  child.width = req.width;							\
-  child.height = allocation->height - 2 * shadow_height;			\
-  child.width = MAX (1, child.width);						\
-  child.height = MAX (1, child.height);						\
-  										\
-  gtk_widget_size_allocate (combo_box->priv->button, &child);
-
-static void
-gtk_combo_box_size_allocate (GtkWidget     *widget,
-                             GtkAllocation *allocation)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-  GtkComboBoxPrivate *priv = combo_box->priv;
-  GtkWidget *child_widget;
-  gint shadow_width, shadow_height;
-  gint focus_width, focus_pad;
-  GtkAllocation child;
-  GtkRequisition req;
-  GtkStyle *style;
-  gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-
-  gtk_widget_set_allocation (widget, allocation);
-  child_widget = gtk_bin_get_child (GTK_BIN (widget));
-
-  style = gtk_widget_get_style (widget);
-  gtk_widget_style_get (widget,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			NULL);
-
-  if (GTK_SHADOW_NONE != priv->shadow_type)
-    {
-      shadow_width = style->xthickness;
-      shadow_height = style->ythickness;
-    }
-  else
-    {
-      shadow_width = 0;
-      shadow_height = 0;
-    }
-
-  if (!priv->tree_view)
-    {
-      if (priv->cell_view)
-        {
-          gint xthickness, ythickness;
-          gint width;
-          guint border_width;
-
-          /* menu mode */
-          allocation->x += shadow_width;
-          allocation->y += shadow_height;
-          allocation->width -= 2 * shadow_width;
-          allocation->height -= 2 * shadow_height;
-
-          gtk_widget_size_allocate (priv->button, allocation);
-
-          /* set some things ready */
-          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button));
-          style = gtk_widget_get_style (priv->button);
-          xthickness = style->xthickness;
-          ythickness = style->ythickness;
-
-          child.x = allocation->x;
-          child.y = allocation->y;
-	  width = allocation->width;
-	  child.height = allocation->height;
-
-	  if (!priv->is_cell_renderer)
-	    {
-	      child.x += border_width + xthickness + focus_width + focus_pad;
-	      child.y += border_width + ythickness + focus_width + focus_pad;
-	      width -= 2 * (child.x - allocation->x);
-	      child.height -= 2 * (child.y - allocation->y);
-	    }
-
-
-          /* handle the children */
-          gtk_widget_get_preferred_size (priv->arrow, &req, NULL);
-          child.width = req.width;
-          if (!is_rtl)
-            child.x += width - req.width;
-	  child.width = MAX (1, child.width);
-	  child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (priv->arrow, &child);
-          if (is_rtl)
-            child.x += req.width;
-          gtk_widget_get_preferred_size (priv->separator, &req, NULL);
-          child.width = req.width;
-          if (!is_rtl)
-            child.x -= req.width;
-	  child.width = MAX (1, child.width);
-	  child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (priv->separator, &child);
-
-          if (is_rtl)
-            {
-              child.x += req.width;
-              child.width = allocation->x + allocation->width 
-                - (border_width + xthickness + focus_width + focus_pad) 
-		- child.x;
-            }
-          else 
-            {
-              child.width = child.x;
-              child.x = allocation->x 
-		+ border_width + xthickness + focus_width + focus_pad;
-              child.width -= child.x;
-            }
-
-          if (gtk_widget_get_visible (priv->popup_widget))
-            {
-              gint width, menu_width;
-
-              if (priv->wrap_width == 0)
-                {
-                  GtkAllocation combo_box_allocation;
-
-                  gtk_widget_get_allocation (GTK_WIDGET (combo_box), &combo_box_allocation);
-                  width = combo_box_allocation.width;
-                  gtk_widget_set_size_request (priv->popup_widget, -1, -1);
-
-		  if (combo_box->priv->popup_fixed_width)
-		    gtk_widget_get_preferred_width (priv->popup_widget, &menu_width, NULL);
-		  else
-		    gtk_widget_get_preferred_width (priv->popup_widget, NULL, &menu_width);
-
-                  gtk_widget_set_size_request (priv->popup_widget,
-					       MAX (width, menu_width), -1);
-               }
-
-              /* reposition the menu after giving it a new width */
-              gtk_menu_reposition (GTK_MENU (priv->popup_widget));
-            }
-
-	  child.width = MAX (1, child.width);
-	  child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (child_widget, &child);
-        }
-      else
-        {
-          GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
-
-          if (is_rtl)
-            child.x = allocation->x + req.width + shadow_width;
-          else
-            child.x = allocation->x + shadow_width;
-          child.y = allocation->y + shadow_height;
-          child.width = allocation->width - req.width - 2 * shadow_width;
-	  child.width = MAX (1, child.width);
-	  child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (child_widget, &child);
-        }
-    }
-  else
-    {
-      /* list mode */
-
-      /* Combobox thickness + border-width */
-      guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-      int delta_x = shadow_width + border_width;
-      int delta_y = shadow_height + border_width;
-
-      /* button */
-      GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
-
-      /* frame */
-      if (is_rtl)
-        child.x = allocation->x + req.width;
-      else
-        child.x = allocation->x;
-
-      child.y = allocation->y;
-      child.width = allocation->width - req.width;
-      child.height = allocation->height;
-
-      if (priv->cell_view_frame)
-        {
-          child.x += delta_x;
-          child.y += delta_y;
-          child.width = MAX (1, child.width - delta_x * 2);
-          child.height = MAX (1, child.height - delta_y * 2);
-          gtk_widget_size_allocate (priv->cell_view_frame, &child);
-
-          /* the sample */
-          if (priv->has_frame)
-            {
-              border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
-              style = gtk_widget_get_style (priv->cell_view_frame);
-              delta_x = border_width + style->xthickness;
-              delta_y = border_width + style->ythickness;
-
-              child.x += delta_x;
-              child.y += delta_y;
-              child.width -= delta_x * 2;
-              child.height -= delta_y * 2;
-            }
-        }
-      else
-        {
-          child.x += delta_x;
-          child.y += delta_y;
-          child.width -= delta_x * 2;
-          child.height -= delta_y * 2;
-        }
-
-      if (gtk_widget_get_visible (priv->popup_window))
-        {
-          gint x, y, width, height;
-          gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
-          gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
-          gtk_widget_set_size_request (priv->popup_window, width, height);
-        }
-
-      
-      child.width = MAX (1, child.width);
-      child.height = MAX (1, child.height);
-      
-      gtk_widget_size_allocate (child_widget, &child);
-    }
-}
-
-#undef GTK_COMBO_BOX_ALLOCATE_BUTTON
-
 static void
 gtk_combo_box_unset_model (GtkComboBox *combo_box)
 {
@@ -3049,6 +3078,11 @@ gtk_combo_box_unset_model (GtkComboBox *combo_box)
 
   if (priv->model)
     {
+      g_signal_handler_disconnect (priv->model,
+				   priv->inserted_id);
+      g_signal_handler_disconnect (priv->model,
+				   priv->deleted_id);
+
       g_object_unref (priv->model);
       priv->model = NULL;
     }
@@ -3301,50 +3335,6 @@ gtk_combo_box_update_sensitivity (GtkComboBox *combo_box)
     gtk_widget_set_sensitive (combo_box->priv->box, sensitive);
 }
 
-static void
-gtk_combo_box_model_row_inserted (GtkTreeModel     *model,
-				  GtkTreePath      *path,
-				  GtkTreeIter      *iter,
-				  gpointer          user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  if (combo_box->priv->tree_view)
-    gtk_combo_box_list_popup_resize (combo_box);
-}
-
-static void
-gtk_combo_box_model_row_deleted (GtkTreeModel     *model,
-				 GtkTreePath      *path,
-				 gpointer          user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  GtkComboBoxPrivate *priv = combo_box->priv;
-
-  if (!gtk_tree_row_reference_valid (priv->active_row))
-    {
-      if (priv->cell_view)
-	gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv->cell_view), NULL);
-      g_signal_emit (combo_box, combo_box_signals[CHANGED], 0);
-    }
-  
-  if (priv->tree_view)
-    gtk_combo_box_list_popup_resize (combo_box);
-}
-
-static void
-gtk_combo_box_model_rows_reordered (GtkTreeModel    *model,
-				    GtkTreePath     *path,
-				    GtkTreeIter     *iter,
-				    gint            *new_order,
-				    gpointer         user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  /* XXX Is this needed ??? */
-  gtk_tree_row_reference_reordered (G_OBJECT (user_data), path, iter, new_order);
-}
-
 static gboolean
 list_popup_resize_idle (gpointer user_data)
 {
@@ -4564,7 +4554,16 @@ gtk_combo_box_set_model (GtkComboBox  *combo_box,
 
   combo_box->priv->model = model;
   g_object_ref (combo_box->priv->model);
-      
+
+  combo_box->priv->inserted_id =
+    g_signal_connect (combo_box->priv->model, "row-inserted",
+		      G_CALLBACK (gtk_combo_box_model_row_inserted),
+		      combo_box);
+  combo_box->priv->deleted_id =
+    g_signal_connect (combo_box->priv->model, "row-deleted",
+		      G_CALLBACK (gtk_combo_box_model_row_deleted),
+		      combo_box);
+
   if (combo_box->priv->tree_view)
     {
       /* list mode */
@@ -4578,7 +4577,6 @@ gtk_combo_box_set_model (GtkComboBox  *combo_box,
       /* menu mode */
       gtk_tree_menu_set_model (GTK_TREE_MENU (combo_box->priv->popup_widget), 
 			       combo_box->priv->model);
-      /* XXX Resize ?? */
     }
 
   if (combo_box->priv->cell_view)



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