X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcombobox.c;h=e7ef489f61fa3c686d7aa0d649140a956cf7d87f;hb=d97861bd8b338c3d25d7ffb5496edee9eee9bfbb;hp=4fdcfe5b0de4cae783905ce24ef6eeadaf215022;hpb=b5c6904c2f77d20e64b86c48b262d7306502a880;p=~andy%2Fgtk diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 4fdcfe5b0..e7ef489f6 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -12,13 +12,14 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" + #include "gtkcombobox.h" + +#include "gtkadjustment.h" #include "gtkcellareabox.h" #include "gtktreemenu.h" #include "gtkarrow.h" @@ -28,18 +29,21 @@ #include "gtkcellview.h" #include "gtkeventbox.h" #include "gtkframe.h" -#include "gtkhbox.h" +#include "gtkbox.h" #include "gtkliststore.h" #include "gtkmain.h" #include "gtkmenuprivate.h" #include "gtkmenushellprivate.h" #include "gtkscrolledwindow.h" #include "gtkseparatormenuitem.h" -#include "gtktearoffmenuitem.h" +#include "deprecated/gtktearoffmenuitem.h" #include "gtktogglebutton.h" #include "gtktreeselection.h" -#include "gtkvseparator.h" +#include "gtkseparator.h" +#include "gtkwidgetpath.h" +#include "gtkwidgetprivate.h" #include "gtkwindow.h" +#include "gtktypebuiltins.h" #include "gtkprivate.h" #include @@ -52,6 +56,7 @@ #include "gtkentryprivate.h" #include "gtktreeprivate.h" +#include "a11y/gtkcomboboxaccessible.h" /** @@ -103,7 +108,6 @@ struct _GtkComboBoxPrivate GtkTreeRowReference *active_row; GtkWidget *tree_view; - GtkTreeViewColumn *column; GtkWidget *cell_view; GtkWidget *cell_view_frame; @@ -128,7 +132,8 @@ struct _GtkComboBoxPrivate guint resize_idle_id; /* For "has-entry" specific behavior we track - * an automated cell renderer and text column */ + * an automated cell renderer and text column + */ gint text_column; GtkCellRenderer *text_renderer; @@ -215,6 +220,7 @@ enum { MOVE_ACTIVE, POPUP, POPDOWN, + FORMAT_ENTRY_TEXT, LAST_SIGNAL }; @@ -242,7 +248,6 @@ enum { static guint combo_box_signals[LAST_SIGNAL] = {0,}; -#define BONUS_PADDING 4 #define SCROLL_TIME 100 /* common */ @@ -265,8 +270,8 @@ static void gtk_combo_box_get_property (GObject *object, GValue *value, GParamSpec *spec); -static void gtk_combo_box_state_changed (GtkWidget *widget, - GtkStateType previous); +static void gtk_combo_box_state_flags_changed (GtkWidget *widget, + GtkStateFlags previous); static void gtk_combo_box_grab_focus (GtkWidget *widget); static void gtk_combo_box_style_updated (GtkWidget *widget); static void gtk_combo_box_button_toggled (GtkWidget *widget, @@ -405,7 +410,7 @@ static void gtk_combo_box_menu_popup (GtkComboBox *combo_box, guint32 activate_time); /* cell layout */ -GtkCellArea *gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout); +static GtkCellArea *gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout); static gboolean gtk_combo_box_mnemonic_activate (GtkWidget *widget, gboolean group_cycling); @@ -420,7 +425,8 @@ static void gtk_combo_box_entry_contents_changed (GtkEntry *e gpointer user_data); static void gtk_combo_box_entry_active_changed (GtkComboBox *combo_box, gpointer user_data); - +static gchar *gtk_combo_box_format_entry_text (GtkComboBox *combo_box, + const gchar *path); /* GtkBuildable method implementation */ static GtkBuildableIface *parent_buildable_iface; @@ -460,7 +466,10 @@ static void gtk_combo_box_get_preferred_height_for_width (GtkWidget *widg gint avail_size, gint *minimum_size, gint *natural_size); - +static GtkWidgetPath *gtk_combo_box_get_path_for_child (GtkContainer *container, + GtkWidget *child); +static void gtk_combo_box_direction_changed (GtkWidget *widget, + GtkTextDirection previous_direction); G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN, G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, @@ -484,6 +493,9 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) container_class->forall = gtk_combo_box_forall; container_class->add = gtk_combo_box_add; container_class->remove = gtk_combo_box_remove; + container_class->get_path_for_child = gtk_combo_box_get_path_for_child; + + gtk_container_class_handle_border_width (container_class); widget_class = (GtkWidgetClass *)klass; widget_class->size_allocate = gtk_combo_box_size_allocate; @@ -492,12 +504,13 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate; widget_class->grab_focus = gtk_combo_box_grab_focus; widget_class->style_updated = gtk_combo_box_style_updated; - widget_class->state_changed = gtk_combo_box_state_changed; + widget_class->state_flags_changed = gtk_combo_box_state_flags_changed; widget_class->get_preferred_width = gtk_combo_box_get_preferred_width; widget_class->get_preferred_height = gtk_combo_box_get_preferred_height; widget_class->get_preferred_height_for_width = gtk_combo_box_get_preferred_height_for_width; widget_class->get_preferred_width_for_height = gtk_combo_box_get_preferred_width_for_height; widget_class->destroy = gtk_combo_box_destroy; + widget_class->direction_changed = gtk_combo_box_direction_changed; object_class = (GObjectClass *)klass; object_class->constructor = gtk_combo_box_constructor; @@ -506,6 +519,8 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) object_class->set_property = gtk_combo_box_set_property; object_class->get_property = gtk_combo_box_get_property; + klass->format_entry_text = gtk_combo_box_format_entry_text; + /* signals */ /** * GtkComboBox::changed: @@ -590,6 +605,58 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) _gtk_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); + /** + * GtkComboBox::format-entry-text: + * @combo: the object which received the signal + * @path: the GtkTreePath string from the combo box's current model to format text for + * + * For combo boxes that are created with an entry (See GtkComboBox:has-entry). + * + * A signal which allows you to change how the text displayed in a combo box's + * entry is displayed. + * + * Connect a signal handler which returns an allocated string representing + * @path. That string will then be used to set the text in the combo box's entry. + * The default signal handler uses the text from the GtkComboBox::entry-text-column + * model column. + * + * Here's an example signal handler which fetches data from the model and + * displays it in the entry. + * |[ + * static gchar* + * format_entry_text_callback (GtkComboBox *combo, + * const gchar *path, + * gpointer user_data) + * { + * GtkTreeIter iter; + * GtkTreeModel model; + * gdouble value; + * + * model = gtk_combo_box_get_model (combo); + * + * gtk_tree_model_get_iter_from_string (model, &iter, path); + * gtk_tree_model_get (model, &iter, + * THE_DOUBLE_VALUE_COLUMN, &value, + * -1); + * + * return g_strdup_printf ("%g", value); + * } + * ]| + * + * Return value: (transfer full): a newly allocated string representing @path + * for the current GtkComboBox model. + * + * Since: 3.4 + */ + combo_box_signals[FORMAT_ENTRY_TEXT] = + g_signal_new (I_("format-entry-text"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkComboBoxClass, format_entry_text), + _gtk_single_string_accumulator, NULL, + _gtk_marshal_STRING__STRING, + G_TYPE_STRING, 1, G_TYPE_STRING); + /* key bindings */ binding_set = gtk_binding_set_by_class (widget_class); @@ -932,6 +999,9 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) * * The #GtkCellArea used to layout cell renderers for this combo box. * + * If no area is specified when creating the combo box with gtk_combo_box_new_with_area() + * a horizontally oriented #GtkCellAreaBox will be used. + * * Since: 3.0 */ g_object_class_install_property (object_class, @@ -968,6 +1038,23 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) 15, GTK_PARAM_READABLE)); + /** + * GtkComboBox:arrow-scaling: + * + * Sets the amount of space used up by the combobox arrow, + * proportional to the font size. + * + * Since: 3.2 + */ + gtk_widget_class_install_style_property (widget_class, + g_param_spec_float ("arrow-scaling", + P_("Arrow Scaling"), + P_("The amount of space used by the arrow"), + 0, + 2.0, + 1.0, + GTK_PARAM_READABLE)); + /** * GtkComboBox:shadow-type: * @@ -984,6 +1071,8 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) GTK_PARAM_READABLE)); g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COMBO_BOX_ACCESSIBLE); } static void @@ -1048,6 +1137,7 @@ gtk_combo_box_set_property (GObject *object, GParamSpec *pspec) { GtkComboBox *combo_box = GTK_COMBO_BOX (object); + GtkComboBoxPrivate *priv = combo_box->priv; GtkCellArea *area; switch (prop_id) @@ -1077,16 +1167,15 @@ gtk_combo_box_set_property (GObject *object, break; case PROP_HAS_FRAME: - combo_box->priv->has_frame = g_value_get_boolean (value); + priv->has_frame = g_value_get_boolean (value); - if (combo_box->priv->has_entry) + if (priv->has_entry) { GtkWidget *child; child = gtk_bin_get_child (GTK_BIN (combo_box)); - gtk_entry_set_has_frame (GTK_ENTRY (child), - combo_box->priv->has_frame); + gtk_entry_set_has_frame (GTK_ENTRY (child), priv->has_frame); } break; @@ -1118,11 +1207,11 @@ gtk_combo_box_set_property (GObject *object, break; case PROP_EDITING_CANCELED: - combo_box->priv->editing_canceled = g_value_get_boolean (value); + priv->editing_canceled = g_value_get_boolean (value); break; case PROP_HAS_ENTRY: - combo_box->priv->has_entry = g_value_get_boolean (value); + priv->has_entry = g_value_get_boolean (value); break; case PROP_ENTRY_TEXT_COLUMN: @@ -1140,9 +1229,17 @@ gtk_combo_box_set_property (GObject *object, case PROP_CELL_AREA: /* Construct-only, can only be assigned once */ area = g_value_get_object (value); - if (area) - combo_box->priv->area = g_object_ref_sink (area); + { + if (priv->area != NULL) + { + g_warning ("cell-area has already been set, ignoring construct property"); + g_object_ref_sink (area); + g_object_unref (area); + } + else + priv->area = g_object_ref_sink (area); + } break; default: @@ -1241,8 +1338,8 @@ gtk_combo_box_get_property (GObject *object, } static void -gtk_combo_box_state_changed (GtkWidget *widget, - GtkStateType previous) +gtk_combo_box_state_flags_changed (GtkWidget *widget, + GtkStateFlags previous) { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; @@ -1253,17 +1350,13 @@ gtk_combo_box_state_changed (GtkWidget *widget, { GtkStyleContext *context; GtkStateFlags state; - GdkRGBA *color; + GdkRGBA color; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_background_color (context, state, &color); - gtk_style_context_get (context, state, - "background-color", &color, - NULL); - - gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), color); - gdk_rgba_free (color); + gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), &color); } } @@ -1289,6 +1382,94 @@ gtk_combo_box_button_state_flags_changed (GtkWidget *widget, gtk_widget_queue_draw (widget); } +static void +gtk_combo_box_invalidate_order_foreach (GtkWidget *widget) +{ + _gtk_widget_invalidate_style_context (widget, GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION); +} + +static void +gtk_combo_box_invalidate_order (GtkComboBox *combo_box) +{ + gtk_container_forall (GTK_CONTAINER (combo_box), + (GtkCallback) gtk_combo_box_invalidate_order_foreach, + NULL); +} + +static void +gtk_combo_box_direction_changed (GtkWidget *widget, + GtkTextDirection previous_direction) +{ + gtk_combo_box_invalidate_order (GTK_COMBO_BOX (widget)); +} + +static GtkWidgetPath * +gtk_combo_box_get_path_for_child (GtkContainer *container, + GtkWidget *child) +{ + GtkComboBoxPrivate *priv = GTK_COMBO_BOX (container)->priv; + GtkWidgetPath *path; + GtkWidget *widget; + gboolean found = FALSE; + GList *visible_children, *l; + GtkWidgetPath *sibling_path; + int pos; + + path = _gtk_widget_create_path (GTK_WIDGET (container)); + + if (gtk_widget_get_visible (child)) + { + visible_children = NULL; + + if (priv->button && gtk_widget_get_visible (priv->button)) + visible_children = g_list_prepend (visible_children, priv->button); + + if (priv->cell_view_frame && gtk_widget_get_visible (priv->cell_view_frame)) + visible_children = g_list_prepend (visible_children, priv->cell_view_frame); + + widget = gtk_bin_get_child (GTK_BIN (container)); + if (widget && gtk_widget_get_visible (widget)) + visible_children = g_list_prepend (visible_children, widget); + + if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) + visible_children = g_list_reverse (visible_children); + + pos = 0; + + for (l = visible_children; l; l = l->next) + { + widget = l->data; + + if (widget == child) + { + found = TRUE; + break; + } + + pos++; + } + } + + if (found) + { + sibling_path = gtk_widget_path_new (); + + for (l = visible_children; l; l = l->next) + gtk_widget_path_append_for_widget (sibling_path, l->data); + + gtk_widget_path_append_with_siblings (path, sibling_path, pos); + + g_list_free (visible_children); + gtk_widget_path_unref (sibling_path); + } + else + { + gtk_widget_path_append_for_widget (path, child); + } + + return path; +} + static void gtk_combo_box_check_appearance (GtkComboBox *combo_box) { @@ -1338,22 +1519,21 @@ gtk_combo_box_style_updated (GtkWidget *widget) GtkComboBoxPrivate *priv = combo_box->priv; GtkWidget *child; + GTK_WIDGET_CLASS (gtk_combo_box_parent_class)->style_updated (widget); + gtk_combo_box_check_appearance (combo_box); if (priv->tree_view && priv->cell_view) { GtkStyleContext *context; - GdkRGBA *color; - - context = gtk_widget_get_style_context (widget); - gtk_style_context_get (context, 0, - "background-color", &color, - NULL); + GtkStateFlags state; + GdkRGBA color; - gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), - color); + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_background_color (context, state, &color); - gdk_rgba_free (color); + gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), &color); } child = gtk_bin_get_child (GTK_BIN (combo_box)); @@ -1660,21 +1840,23 @@ gtk_combo_box_set_popup_widget (GtkComboBox *combo_box, } static void -get_widget_border (GtkWidget *widget, - GtkBorder *border) +get_widget_padding_and_border (GtkWidget *widget, + GtkBorder *padding) { GtkStyleContext *context; - GtkBorder *border_width; + GtkStateFlags state; + GtkBorder tmp; context = gtk_widget_get_style_context (widget); + state = gtk_style_context_get_state (context); - gtk_style_context_get (context, - gtk_widget_get_state_flags (widget), - "border-width", &border_width, - NULL); + gtk_style_context_get_padding (context, state, padding); + gtk_style_context_get_border (context, state, &tmp); - *border = *border_width; - gtk_border_free (border_width); + padding->top += tmp.top; + padding->right += tmp.right; + padding->bottom += tmp.bottom; + padding->left += tmp.left; } static void @@ -1692,7 +1874,7 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, GdkScreen *screen; gint monitor_num; GdkRectangle monitor; - GtkBorder border; + GtkBorder padding; /* FIXME: is using the size request here broken? */ child = gtk_bin_get_child (GTK_BIN (combo_box)); @@ -1709,8 +1891,12 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, gdk_window_get_root_coords (gtk_widget_get_window (child), sx, sy, &sx, &sy); - get_widget_border (GTK_WIDGET (combo_box), &border); - sx -= border.left; + get_widget_padding_and_border (GTK_WIDGET (combo_box), &padding); + + if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL) + sx += padding.left; + else + sx -= padding.left; if (combo_box->priv->popup_fixed_width) gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL); @@ -1726,7 +1912,7 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, 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_geometry (screen, monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); if (*x < monitor.x) *x = monitor.x; @@ -1925,7 +2111,7 @@ gtk_combo_box_list_position (GtkComboBox *combo_box, screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); monitor_num = gdk_screen_get_monitor_at_window (screen, window); - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL) *x = *x + allocation.width - *width; @@ -1960,12 +2146,12 @@ gtk_combo_box_list_position (GtkComboBox *combo_box, } static gboolean -cell_view_is_sensitive (GtkCellView *cell_view) +cell_layout_is_sensitive (GtkCellLayout *layout) { GList *cells, *list; gboolean sensitive; - cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view)); + cells = gtk_cell_layout_get_cells (layout); sensitive = FALSE; for (list = cells; list; list = list->next) @@ -1980,16 +2166,22 @@ cell_view_is_sensitive (GtkCellView *cell_view) return sensitive; } +static gboolean +cell_is_sensitive (GtkCellRenderer *cell, + gpointer data) +{ + gboolean *sensitive = data; + + g_object_get (cell, "sensitive", sensitive, NULL); + + return *sensitive; +} + static gboolean tree_column_row_is_sensitive (GtkComboBox *combo_box, GtkTreeIter *iter) { GtkComboBoxPrivate *priv = combo_box->priv; - GList *cells, *list; - gboolean sensitive; - - if (!priv->column) - return TRUE; if (priv->row_separator_func) { @@ -1998,23 +2190,20 @@ tree_column_row_is_sensitive (GtkComboBox *combo_box, return FALSE; } - gtk_tree_view_column_cell_set_cell_data (priv->column, - priv->model, - iter, FALSE, FALSE); + if (priv->area) + { + gboolean sensitive; - cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->column)); + gtk_cell_area_apply_attributes (priv->area, priv->model, iter, FALSE, FALSE); - sensitive = FALSE; - for (list = cells; list; list = list->next) - { - g_object_get (list->data, "sensitive", &sensitive, NULL); + sensitive = FALSE; - if (sensitive) - break; + gtk_cell_area_foreach (priv->area, cell_is_sensitive, &sensitive); + + return sensitive; } - g_list_free (cells); - return sensitive; + return TRUE; } static void @@ -2048,7 +2237,7 @@ update_menu_sensitivity (GtkComboBox *combo_box, } else { - sensitive = cell_view_is_sensitive (GTK_CELL_VIEW (cell_view)); + sensitive = cell_layout_is_sensitive (GTK_CELL_LAYOUT (cell_view)); if (menu != priv->popup_widget && child == children) { @@ -2341,22 +2530,24 @@ gtk_combo_box_popdown (GtkComboBox *combo_box) priv->grab_keyboard = NULL; } -#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 + border.right; \ - else \ - child.x = allocation->x + allocation->width - req.width - border.left; \ - \ - child.y = allocation->y + border.top; \ - child.width = req.width; \ - child.height = allocation->height - (border.top + border.bottom); \ - child.width = MAX (1, child.width); \ - child.height = MAX (1, child.height); \ - \ - gtk_widget_size_allocate (combo_box->priv->button, &child); +#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON \ + GtkAllocation button_allocation; \ + gtk_widget_get_preferred_size (combo_box->priv->button, \ + &req, NULL); \ + \ + if (is_rtl) \ + button_allocation.x = allocation->x; \ + else \ + button_allocation.x = allocation->x + allocation->width \ + - req.width; \ + \ + button_allocation.y = allocation->y; \ + button_allocation.width = MAX (1, req.width); \ + button_allocation.height = allocation->height; \ + button_allocation.height = MAX (1, button_allocation.height); \ + \ + gtk_widget_size_allocate (combo_box->priv->button, \ + &button_allocation); static void @@ -2366,41 +2557,37 @@ gtk_combo_box_size_allocate (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; GtkWidget *child_widget; - gint focus_width, focus_pad; GtkAllocation child; GtkRequisition req; gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; - GtkBorder border; + GtkBorder padding; gtk_widget_set_allocation (widget, allocation); child_widget = gtk_bin_get_child (GTK_BIN (widget)); - get_widget_border (widget, &border); + get_widget_padding_and_border (widget, &padding); - gtk_widget_style_get (widget, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - NULL); + allocation->x += padding.left; + allocation->y += padding.top; + allocation->width -= padding.left + padding.right; + allocation->height -= padding.top + padding.bottom; if (!priv->tree_view) { if (priv->cell_view) { - GtkBorder button_border; + GtkBorder button_padding; gint width; guint border_width; - /* menu mode */ - allocation->x += border.left; - allocation->y += border.top; - allocation->width -= border.left + border.right; - allocation->height -= border.top + border.bottom; + border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button)); + get_widget_padding_and_border (priv->button, &button_padding); + /* menu mode; child_widget is priv->cell_view. + * Allocate the button to the full combobox allocation (minus the + * padding). + */ gtk_widget_size_allocate (priv->button, allocation); - /* set some things ready */ - border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button)); - get_widget_border (priv->button, &button_border); - child.x = allocation->x; child.y = allocation->y; width = allocation->width; @@ -2408,44 +2595,37 @@ gtk_combo_box_size_allocate (GtkWidget *widget, if (!priv->is_cell_renderer) { - child.x += border_width + button_border.left + focus_width + focus_pad; - child.y += border_width + button_border.top + focus_width + focus_pad; - width -= (2 * (border_width + focus_width + focus_pad)) + - button_border.left + button_border.right; - child.height -= (2 * (border_width + focus_width + focus_pad)) + - button_border.top + button_border.bottom; + /* restrict allocation of the child into the button box + * if we're not in cell renderer mode. + */ + child.x += border_width + button_padding.left; + child.y += border_width + button_padding.top; + width -= 2 * border_width + + button_padding.left + button_padding.right; + child.height -= 2 * border_width + + button_padding.top + button_padding.bottom; } - /* handle the children */ - gtk_widget_get_preferred_size (priv->arrow, &req, NULL); + /* allocate the box containing the separator and the arrow */ + gtk_widget_get_preferred_size (priv->box, &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); + gtk_widget_size_allocate (priv->box, &child); if (is_rtl) { child.x += req.width; child.width = allocation->x + allocation->width - - (border_width + button_border.right + focus_width + focus_pad) - - child.x; + - border_width - child.x - button_padding.right; } else { child.width = child.x; child.x = allocation->x - + border_width + button_border.left + focus_width + focus_pad; + + border_width + button_padding.left; child.width -= child.x; } @@ -2480,66 +2660,66 @@ gtk_combo_box_size_allocate (GtkWidget *widget, } else { + /* menu mode; child_widget has been set with gtk_container_add(). + * E.g. it might be a GtkEntry if priv->has_entry is TRUE. + * Allocate the button at the far end, according to the direction + * of the widget. + */ GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON + /* After the macro, button_allocation has the button allocation rect */ + if (is_rtl) - child.x = allocation->x + req.width + border.right; + child.x = button_allocation.x + button_allocation.width; else - child.x = allocation->x + border.left; - child.y = allocation->y + border.top; - child.width = allocation->width - req.width - (border.left + border.right); + child.x = allocation->x; + + child.y = allocation->y; + child.width = allocation->width - button_allocation.width; + child.height = button_allocation.height; + child.width = MAX (1, child.width); - child.height = MAX (1, child.height); + gtk_widget_size_allocate (child_widget, &child); } } else { - /* list mode */ - guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + /* list mode; child_widget might be either priv->cell_view or a child + * added with gtk_container_add(). + */ - /* button */ + /* After the macro, button_allocation has the button allocation rect */ GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON - /* frame */ if (is_rtl) - child.x = allocation->x + req.width; + child.x = button_allocation.x + button_allocation.width; else child.x = allocation->x; child.y = allocation->y; - child.width = allocation->width - req.width; - child.height = allocation->height; + child.width = allocation->width - button_allocation.width; + child.height = button_allocation.height; if (priv->cell_view_frame) { - child.x += border.left + border_width; - child.y += border.top + border_width; - child.width = MAX (1, child.width - (2 * border_width) - (border.left + border.right)); - child.height = MAX (1, child.height - (2 * border_width) - (border.top + border.bottom)); gtk_widget_size_allocate (priv->cell_view_frame, &child); - /* the sample */ + /* restrict allocation of the child into the frame box if it's present */ if (priv->has_frame) { - GtkBorder frame_border; + GtkBorder frame_padding; + guint border_width; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); - get_widget_border (priv->cell_view_frame, &frame_border); + get_widget_padding_and_border (priv->cell_view_frame, &frame_padding); - child.x += border_width + frame_border.left; - child.y += border_width + frame_border.right; - child.width -= (2 * border_width) + frame_border.left + frame_border.right; - child.height -= (2 * border_width) + frame_border.top + frame_border.bottom; + child.x += border_width + frame_padding.left; + child.y += border_width + frame_padding.right; + child.width -= (2 * border_width) + frame_padding.left + frame_padding.right; + child.height -= (2 * border_width) + frame_padding.top + frame_padding.bottom; } } - else - { - child.x += border.left + border_width; - child.y += border.top + border_width; - child.width -= (2 * border_width) - (border.left + border.right); - child.height -= (2 * border_width) - (border.top + border.bottom); - } if (gtk_widget_get_visible (priv->popup_window)) { @@ -2549,6 +2729,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gtk_widget_set_size_request (priv->popup_window, width, height); } + /* allocate the child */ child.width = MAX (1, child.width); child.height = MAX (1, child.height); gtk_widget_size_allocate (child_widget, &child); @@ -2643,11 +2824,8 @@ gtk_combo_box_draw (GtkWidget *widget, if (priv->shadow_type != GTK_SHADOW_NONE) { GtkStyleContext *context; - GtkStateFlags state; context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - gtk_style_context_set_state (context, state); gtk_render_background (context, cr, 0, 0, gtk_widget_get_allocated_width (widget), @@ -2962,6 +3140,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (priv->box), priv->arrow); + gtk_widget_add_events (priv->button, GDK_SCROLL_MASK); gtk_widget_show_all (priv->button); } @@ -2978,6 +3157,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow); + gtk_widget_add_events (priv->button, GDK_SCROLL_MASK); gtk_widget_show_all (priv->button); } @@ -3012,8 +3192,6 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, (GtkTreeMenuHeaderFunc)gtk_combo_box_header_func, combo_box, NULL); - gtk_widget_set_name (menu, "gtk-combobox-popup-menu"); - g_signal_connect (menu, "key-press-event", G_CALLBACK (gtk_combo_box_menu_key_press), combo_box); gtk_combo_box_set_popup_widget (combo_box, menu); @@ -3047,8 +3225,6 @@ gtk_combo_box_menu_destroy (GtkComboBox *combo_box) priv->arrow = NULL; priv->separator = NULL; - priv->column = NULL; - /* changing the popup window will unref the menu and the children */ } @@ -3062,7 +3238,7 @@ gtk_combo_box_menu_button_press (GtkWidget *widget, GtkComboBoxPrivate *priv = combo_box->priv; if (GTK_IS_MENU (priv->popup_widget) && - event->type == GDK_BUTTON_PRESS && event->button == 1) + event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) { if (priv->focus_on_click && !gtk_widget_has_focus (priv->button)) @@ -3267,17 +3443,13 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) { GtkStyleContext *context; GtkStateFlags state; - GdkRGBA *color; + GdkRGBA color; - context = gtk_widget_get_style_context (widget); + context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_background_color (context, state, &color); - gtk_style_context_get (context, state, - "background-color", &color, - NULL); - - gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), color); - gdk_rgba_free (color); + gtk_cell_view_set_background_rgba (GTK_CELL_VIEW (priv->cell_view), &color); priv->box = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->box), @@ -3324,8 +3496,8 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) if (priv->model) gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), priv->model); - priv->column = gtk_tree_view_column_new_with_area (priv->area); - gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), priv->column); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), + gtk_tree_view_column_new_with_area (priv->area)); if (gtk_tree_row_reference_valid (priv->active_row)) { @@ -3631,35 +3803,35 @@ gtk_combo_box_list_auto_scroll (GtkComboBox *combo_box, gtk_widget_get_allocation (tree_view, &allocation); adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window)); - if (adj && adj->upper - adj->lower > adj->page_size) + if (adj && gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj) > gtk_adjustment_get_page_size (adj)) { if (x <= allocation.x && - adj->lower < adj->value) + gtk_adjustment_get_lower (adj) < gtk_adjustment_get_value (adj)) { - value = adj->value - (allocation.x - x + 1); + value = gtk_adjustment_get_value (adj) - (allocation.x - x + 1); gtk_adjustment_set_value (adj, value); } else if (x >= allocation.x + allocation.width && - adj->upper - adj->page_size > adj->value) + gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj) > gtk_adjustment_get_value (adj)) { - value = adj->value + (x - allocation.x - allocation.width + 1); + value = gtk_adjustment_get_value (adj) + (x - allocation.x - allocation.width + 1); gtk_adjustment_set_value (adj, MAX (value, 0.0)); } } adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window)); - if (adj && adj->upper - adj->lower > adj->page_size) + if (adj && gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj) > gtk_adjustment_get_page_size (adj)) { if (y <= allocation.y && - adj->lower < adj->value) + gtk_adjustment_get_lower (adj) < gtk_adjustment_get_value (adj)) { - value = adj->value - (allocation.y - y + 1); + value = gtk_adjustment_get_value (adj) - (allocation.y - y + 1); gtk_adjustment_set_value (adj, value); } else if (y >= allocation.height && - adj->upper - adj->page_size > adj->value) + gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj) > gtk_adjustment_get_value (adj)) { - value = adj->value + (y - allocation.height + 1); + value = gtk_adjustment_get_value (adj) + (y - allocation.height + 1); gtk_adjustment_set_value (adj, MAX (value, 0.0)); } } @@ -3729,13 +3901,15 @@ gtk_combo_box_list_select_func (GtkTreeSelection *selection, NULL); if (cell_visible && cell_sensitive) - break; + { + sensitive = TRUE; + break; + } cell = cell->next; } - g_list_free (cells); - sensitive = cell_sensitive; + g_list_free (cells); } g_list_free (columns); @@ -3755,10 +3929,19 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model, /* * GtkCellLayout implementation */ -GtkCellArea * -gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout) +static GtkCellArea * +gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout) { - return GTK_COMBO_BOX (cell_layout)->priv->area; + GtkComboBox *combo = GTK_COMBO_BOX (cell_layout); + GtkComboBoxPrivate *priv = combo->priv; + + if (G_UNLIKELY (!priv->area)) + { + priv->area = gtk_cell_area_box_new (); + g_object_ref_sink (priv->area); + } + + return priv->area; } /* @@ -4502,7 +4685,6 @@ static void gtk_combo_box_entry_active_changed (GtkComboBox *combo_box, gpointer user_data) { - GtkComboBoxPrivate *priv = combo_box->priv; GtkTreeModel *model; GtkTreeIter iter; @@ -4512,26 +4694,58 @@ gtk_combo_box_entry_active_changed (GtkComboBox *combo_box, if (entry) { - GValue value = {0,}; + GtkTreePath *path; + gchar *path_str; + gchar *text = NULL; + + model = gtk_combo_box_get_model (combo_box); + path = gtk_tree_model_get_path (model, &iter); + path_str = gtk_tree_path_to_string (path); g_signal_handlers_block_by_func (entry, gtk_combo_box_entry_contents_changed, combo_box); - model = gtk_combo_box_get_model (combo_box); - gtk_tree_model_get_value (model, &iter, - priv->text_column, &value); - g_object_set_property (G_OBJECT (entry), "text", &value); - g_value_unset (&value); + g_signal_emit (combo_box, combo_box_signals[FORMAT_ENTRY_TEXT], 0, + path_str, &text); + + gtk_entry_set_text (entry, text); g_signal_handlers_unblock_by_func (entry, gtk_combo_box_entry_contents_changed, combo_box); + + gtk_tree_path_free (path); + g_free (text); + g_free (path_str); } } } +static gchar * +gtk_combo_box_format_entry_text (GtkComboBox *combo_box, + const gchar *path) +{ + GtkComboBoxPrivate *priv = combo_box->priv; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *text = NULL; + + if (priv->text_column >= 0) + { + model = gtk_combo_box_get_model (combo_box); + gtk_tree_model_get_iter_from_string (model, &iter, path); + + gtk_tree_model_get (model, &iter, + priv->text_column, &text, + -1); + } + + return text; +} + + static GObject * gtk_combo_box_constructor (GType type, guint n_construct_properties, @@ -4540,7 +4754,6 @@ gtk_combo_box_constructor (GType type, GObject *object; GtkComboBox *combo_box; GtkComboBoxPrivate *priv; - GtkStyleContext *context; object = G_OBJECT_CLASS (gtk_combo_box_parent_class)->constructor (type, n_construct_properties, construct_properties); @@ -4550,9 +4763,8 @@ gtk_combo_box_constructor (GType type, if (!priv->area) { - GtkCellArea *area = gtk_cell_area_box_new (); - - priv->area = g_object_ref_sink (area); + priv->area = gtk_cell_area_box_new (); + g_object_ref_sink (priv->area); } priv->cell_view = gtk_cell_view_new_with_context (priv->area, NULL); @@ -4564,17 +4776,18 @@ gtk_combo_box_constructor (GType type, gtk_combo_box_check_appearance (combo_box); - context = gtk_widget_get_style_context (GTK_WIDGET (combo_box)); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); - if (priv->has_entry) { GtkWidget *entry; + GtkStyleContext *context; entry = gtk_entry_new (); gtk_widget_show (entry); gtk_container_add (GTK_CONTAINER (combo_box), entry); + context = gtk_widget_get_style_context (GTK_WIDGET (combo_box)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_COMBOBOX_ENTRY); + priv->text_renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), priv->text_renderer, TRUE); @@ -4817,7 +5030,7 @@ gtk_combo_box_set_add_tearoffs (GtkComboBox *combo_box, * * Since: 2.10 */ -G_CONST_RETURN gchar* +const gchar* gtk_combo_box_get_title (GtkComboBox *combo_box) { g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL); @@ -4943,7 +5156,7 @@ gtk_combo_box_get_popup_accessible (GtkComboBox *combo_box) } /** - * gtk_combo_box_get_row_separator_func: + * gtk_combo_box_get_row_separator_func: (skip) * @combo_box: a #GtkComboBox * * Returns the current row separator function. @@ -5230,17 +5443,14 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; - gint focus_width, focus_pad; gint font_size, arrow_size; PangoContext *context; PangoFontMetrics *metrics; - PangoFontDescription *font_desc; GtkWidget *child; gint minimum_width = 0, natural_width = 0; gint child_min, child_nat; - GtkStyleContext *style_context; - GtkStateFlags state; - GtkBorder *border; + GtkBorder padding; + gfloat arrow_scaling; child = gtk_bin_get_child (GTK_BIN (widget)); @@ -5248,28 +5458,21 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, 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, + "arrow-scaling", &arrow_scaling, NULL); - style_context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - - gtk_style_context_get (style_context, state, - "font", &font_desc, - "border-width", &border, - NULL); + get_widget_padding_and_border (widget, &padding); context = gtk_widget_get_pango_context (GTK_WIDGET (widget)); - metrics = pango_context_get_metrics (context, font_desc, + metrics = pango_context_get_metrics (context, + pango_context_get_font_description (context), 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); - pango_font_description_free (font_desc); - arrow_size = MAX (arrow_size, font_size); + arrow_size = MAX (arrow_size, font_size) * arrow_scaling; gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size); @@ -5278,21 +5481,16 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, /* menu mode */ if (priv->cell_view) { - gint sep_width, arrow_width; - gint border_width, xpad; - GtkBorder button_border; - - border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); - get_widget_border (priv->button, &button_border); + gint box_width, xpad; + GtkBorder button_padding; - gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL); - gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL); + get_widget_padding_and_border (priv->button, &button_padding); - xpad = 2 * (border_width + focus_width + focus_pad) + - button_border.left + button_border.right; + gtk_widget_get_preferred_width (priv->box, &box_width, NULL); + xpad = button_padding.left + button_padding.right + padding.left + padding.right; - minimum_width = child_min + sep_width + arrow_width + xpad; - natural_width = child_nat + sep_width + arrow_width + xpad; + minimum_width = child_min + box_width + xpad; + natural_width = child_nat + box_width + xpad; } else { @@ -5314,19 +5512,16 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, 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, xpad; - GtkBorder frame_border; + GtkBorder frame_padding; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); - get_widget_border (priv->cell_view_frame, &frame_border); - xpad = (2 * border_width) + frame_border.left + frame_border.right; + get_widget_padding_and_border (priv->cell_view_frame, &frame_padding); + xpad = (2 * border_width) + frame_padding.left + frame_padding.right; minimum_width += xpad; natural_width += xpad; @@ -5341,9 +5536,8 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, natural_width += button_nat_width; } - minimum_width += border->left + border->right; - natural_width += border->left + border->right; - gtk_border_free (border); + minimum_width += padding.left + padding.right; + natural_width += padding.left + padding.right; if (minimum_size) *minimum_size = minimum_width; @@ -5385,21 +5579,15 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; - gint focus_width, focus_pad; gint min_height = 0, nat_height = 0; gint size; GtkWidget *child; - GtkBorder border; - - gtk_widget_style_get (GTK_WIDGET (widget), - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - NULL); + GtkBorder padding; child = gtk_bin_get_child (GTK_BIN (widget)); - get_widget_border (widget, &border); - size = avail_size - border.left; + get_widget_padding_and_border (widget, &padding); + size = avail_size; if (!priv->tree_view) { @@ -5407,34 +5595,27 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, if (priv->cell_view) { /* calculate x/y padding and separator/arrow size */ - gint sep_width, arrow_width, sep_height, arrow_height; - gint border_width, xpad, ypad; - GtkBorder button_border; + gint box_width, box_height; + gint xpad, ypad; + GtkBorder button_padding; - border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); - get_widget_border (priv->button, &button_border); + get_widget_padding_and_border (priv->button, &button_padding); - 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); + gtk_widget_get_preferred_width (priv->box, &box_width, NULL); + gtk_widget_get_preferred_height_for_width (priv->box, + box_width, &box_height, NULL); - xpad = 2 * (border_width + focus_width + focus_pad) + - button_border.left + button_border.right; - ypad = 2 * (border_width + focus_width + focus_pad) + - button_border.top + button_border.bottom; + xpad = button_padding.left + button_padding.right; + ypad = button_padding.top + button_padding.bottom; - size -= sep_width + arrow_width + xpad; + size -= box_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 = MAX (min_height, box_height); + nat_height = MAX (nat_height, box_height); min_height += ypad; nat_height += ypad; @@ -5470,18 +5651,17 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, if (priv->cell_view_frame && priv->has_frame) { - GtkBorder frame_border; + GtkBorder frame_padding; gint border_width; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); - get_widget_border (GTK_WIDGET (priv->cell_view_frame), &frame_border); + get_widget_padding_and_border (GTK_WIDGET (priv->cell_view_frame), &frame_padding); - xpad = (2 * border_width) + border.left + frame_border.right; - ypad = (2 * border_width) + border.top + frame_border.bottom; + xpad = (2 * border_width) + padding.left + frame_padding.right; + ypad = (2 * border_width) + padding.top + frame_padding.bottom; } size -= but_width; - size -= 2 * focus_width; size -= xpad; /* Get height-for-width of the child widget, usually a GtkCellArea calculating @@ -5495,8 +5675,8 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, nat_height += ypad; } - min_height += border.top + border.bottom; - nat_height += border.top + border.bottom; + min_height += padding.top + padding.bottom; + nat_height += padding.top + padding.bottom; if (minimum_size) *minimum_size = min_height; @@ -5564,15 +5744,16 @@ gtk_combo_box_get_id_column (GtkComboBox *combo_box) * @combo_box: a #GtkComboBox * * Returns the ID of the active row of @combo_box. This value is taken - * from the active row and the column specified by the 'id-column' + * from the active row and the column specified by the #GtkComboBox:id-column * property of @combo_box (see gtk_combo_box_set_id_column()). * * The returned value is an interned string which means that you can * compare the pointer by value to other interned strings and that you * must not free it. * - * If the 'id-column' property of @combo_box is not set or if no row is - * selected then %NULL is returned. + * If the #GtkComboBox:id-column property of @combo_box is not set, or if + * no row is active, or if the active row has a %NULL ID value, then %NULL + * is returned. * * Return value: the ID of the active row, or %NULL * @@ -5585,7 +5766,7 @@ gtk_combo_box_get_active_id (GtkComboBox *combo_box) GtkTreeIter iter; gint column; - g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0); + g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL); column = combo_box->priv->id_column; @@ -5614,41 +5795,54 @@ gtk_combo_box_get_active_id (GtkComboBox *combo_box) /** * gtk_combo_box_set_active_id: * @combo_box: a #GtkComboBox - * @active_id: the ID of the row to select + * @active_id: (allow-none): the ID of the row to select, or %NULL + * + * Changes the active row of @combo_box to the one that has an ID equal to + * @active_id, or unsets the active row if @active_id is %NULL. Rows having + * a %NULL ID string cannot be made active by this function. * - * Changes the active row of @combo_box to the one that has an ID equal to @id. + * If the #GtkComboBox:id-column property of @combo_box is unset or if no + * row has the given ID then the function does nothing and returns %FALSE. * - * If the 'id-column' property of @combo_box is unset or if no row has - * the given ID then nothing happens. + * Returns: %TRUE if a row with a matching ID was found. If a %NULL + * @active_id was given to unset the active row, the function + * always returns %TRUE. * * Since: 3.0 **/ -void +gboolean gtk_combo_box_set_active_id (GtkComboBox *combo_box, const gchar *active_id) { GtkTreeModel *model; GtkTreeIter iter; + gboolean match = FALSE; gint column; - g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); + g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE); + + if (active_id == NULL) + { + gtk_combo_box_set_active (combo_box, -1); + return TRUE; /* active row was successfully unset */ + } column = combo_box->priv->id_column; if (column < 0) - return; + return FALSE; model = gtk_combo_box_get_model (combo_box); - g_return_if_fail (gtk_tree_model_get_column_type (model, column) == - G_TYPE_STRING); + g_return_val_if_fail (gtk_tree_model_get_column_type (model, column) == + G_TYPE_STRING, FALSE); if (gtk_tree_model_get_iter_first (model, &iter)) do { - gboolean match; gchar *id; gtk_tree_model_get (model, &iter, column, &id, -1); - match = strcmp (id, active_id) == 0; + if (id != NULL) + match = strcmp (id, active_id) == 0; g_free (id); if (match) @@ -5657,4 +5851,6 @@ gtk_combo_box_set_active_id (GtkComboBox *combo_box, break; } } while (gtk_tree_model_iter_next (model, &iter)); + + return match; }