[gtk+/combo-refactor: 32/32] Fixing up the combo box gtktreemodel listener signals.
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/combo-refactor: 32/32] Fixing up the combo box gtktreemodel listener signals.
- Date: Thu, 25 Nov 2010 06:08:42 +0000 (UTC)
commit 1860879b62931d44e83819012be19c23530f36cd
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]