X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcombobox.c;h=794cd00dd33688d706377bc942035cf8f1863320;hb=3b2182e711ace4a2d6843848208224cd7525d530;hp=6986db25d8f98476abb733701ae2c89369e0edbb;hpb=7e22b46c1f5c7cc15e18283932497760705f03a3;p=~andy%2Fgtk diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 6986db25d..794cd00dd 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,17 +29,19 @@ #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 "gtkseparator.h" +#include "gtkwidgetpath.h" +#include "gtkwidgetprivate.h" #include "gtkwindow.h" #include "gtktypebuiltins.h" #include "gtkprivate.h" @@ -217,6 +220,7 @@ enum { MOVE_ACTIVE, POPUP, POPDOWN, + FORMAT_ENTRY_TEXT, LAST_SIGNAL }; @@ -244,7 +248,6 @@ enum { static guint combo_box_signals[LAST_SIGNAL] = {0,}; -#define BONUS_PADDING 4 #define SCROLL_TIME 100 /* common */ @@ -422,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; @@ -462,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, @@ -486,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; @@ -500,6 +510,7 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) 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; @@ -508,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: @@ -592,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); @@ -1317,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) { @@ -1687,16 +1840,23 @@ gtk_combo_box_set_popup_widget (GtkComboBox *combo_box, } static void -get_widget_padding (GtkWidget *widget, - GtkBorder *padding) +get_widget_padding_and_border (GtkWidget *widget, + GtkBorder *padding) { GtkStyleContext *context; GtkStateFlags state; + GtkBorder tmp; context = gtk_widget_get_style_context (widget); state = gtk_style_context_get_state (context); gtk_style_context_get_padding (context, state, padding); + gtk_style_context_get_border (context, state, &tmp); + + padding->top += tmp.top; + padding->right += tmp.right; + padding->bottom += tmp.bottom; + padding->left += tmp.left; } static void @@ -1731,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_padding (GTK_WIDGET (combo_box), &padding); - sx -= padding.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); @@ -1748,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; @@ -1947,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; @@ -2167,6 +2331,19 @@ popup_grab_on_window (GdkWindow *window, return TRUE; } +static gboolean +gtk_combo_box_grab_broken_event (GtkWidget *widget, + GdkEventGrabBroken *event, + gpointer user_data) +{ + GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); + + if (event->grab_window == NULL) + gtk_combo_box_popdown (combo_box); + + return TRUE; +} + /** * gtk_combo_box_popup: * @combo_box: a #GtkComboBox @@ -2291,6 +2468,11 @@ gtk_combo_box_popup_for_device (GtkComboBox *combo_box, gtk_device_grab_add (priv->popup_window, pointer, TRUE); priv->grab_pointer = pointer; priv->grab_keyboard = keyboard; + + g_signal_connect (priv->popup_window, + "grab-broken-event", + G_CALLBACK (gtk_combo_box_grab_broken_event), + combo_box); } static void @@ -2357,6 +2539,10 @@ gtk_combo_box_popdown (GtkComboBox *combo_box) if (!gtk_widget_get_realized (GTK_WIDGET (combo_box))) return; + if (priv->grab_keyboard) + gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME); + gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME); + gtk_device_grab_remove (priv->popup_window, priv->grab_pointer); gtk_widget_hide (priv->popup_window); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), @@ -2366,22 +2552,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 + padding.right; \ - else \ - child.x = allocation->x + allocation->width - req.width - padding.left; \ - \ - child.y = allocation->y + padding.top; \ - child.width = req.width; \ - child.height = allocation->height - (padding.top + padding.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 @@ -2391,7 +2579,6 @@ 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; @@ -2399,12 +2586,12 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gtk_widget_set_allocation (widget, allocation); child_widget = gtk_bin_get_child (GTK_BIN (widget)); - get_widget_padding (widget, &padding); + 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) { @@ -2414,17 +2601,14 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gint width; guint border_width; - gtk_widget_size_allocate (priv->button, allocation); - - /* menu mode */ - allocation->x += padding.left; - allocation->y += padding.top; - allocation->width -= padding.left + padding.right; - allocation->height -= padding.top + padding.bottom; - - /* set some things ready */ border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button)); - get_widget_padding (priv->button, &button_padding); + 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); child.x = allocation->x; child.y = allocation->y; @@ -2433,44 +2617,37 @@ gtk_combo_box_size_allocate (GtkWidget *widget, if (!priv->is_cell_renderer) { - child.x += border_width + button_padding.left + focus_width + focus_pad; - child.y += border_width + button_padding.top + focus_width + focus_pad; - width -= (2 * (border_width + focus_width + focus_pad)) + + /* 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 + focus_width + focus_pad)) + + child.height -= 2 * border_width + button_padding.top + button_padding.bottom; } - /* handle the children */ - gtk_widget_get_preferred_size (priv->arrow, &req, NULL); - child.width = req.width; - if (!is_rtl) - child.x += width - req.width - button_padding.right; - 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); + /* 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 -= req.width; + child.x += width - 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 + 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_padding.left + focus_width + focus_pad; + + border_width + button_padding.left; child.width -= child.x; } @@ -2505,52 +2682,59 @@ 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 + padding.right; + child.x = button_allocation.x + button_allocation.width; else - child.x = allocation->x + padding.left; - child.y = allocation->y + padding.top; - child.width = allocation->width - req.width - (padding.left + padding.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 += padding.left + border_width; - child.y += padding.top + border_width; - child.width = MAX (1, child.width - (2 * border_width) - (padding.left + padding.right)); - child.height = MAX (1, child.height - (2 * border_width) - (padding.top + padding.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_padding; + guint border_width; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); - get_widget_padding (priv->cell_view_frame, &frame_padding); + get_widget_padding_and_border (priv->cell_view_frame, &frame_padding); child.x += border_width + frame_padding.left; child.y += border_width + frame_padding.right; @@ -2558,13 +2742,6 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child.height -= (2 * border_width) + frame_padding.top + frame_padding.bottom; } } - else - { - child.x += padding.left + border_width; - child.y += padding.top + border_width; - child.width -= (2 * border_width) - (padding.left + padding.right); - child.height -= (2 * border_width) - (padding.top + padding.bottom); - } if (gtk_widget_get_visible (priv->popup_window)) { @@ -2574,6 +2751,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); @@ -2668,11 +2846,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), @@ -2987,6 +3162,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); } @@ -3003,6 +3179,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); } @@ -3083,7 +3260,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)) @@ -3746,13 +3923,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); @@ -4528,7 +4707,6 @@ static void gtk_combo_box_entry_active_changed (GtkComboBox *combo_box, gpointer user_data) { - GtkComboBoxPrivate *priv = combo_box->priv; GtkTreeModel *model; GtkTreeIter iter; @@ -4538,26 +4716,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, @@ -5255,16 +5465,12 @@ 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; - const PangoFontDescription *font_desc; GtkWidget *child; gint minimum_width = 0, natural_width = 0; gint child_min, child_nat; - GtkStyleContext *style_context; - GtkStateFlags state; GtkBorder padding; gfloat arrow_scaling; @@ -5274,20 +5480,15 @@ 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); - - get_widget_padding (widget, &padding); - font_desc = gtk_style_context_get_font (style_context, state); + 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)); @@ -5302,21 +5503,16 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, /* menu mode */ if (priv->cell_view) { - gint sep_width, arrow_width; - gint border_width, xpad; + gint box_width, xpad; GtkBorder button_padding; - border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); - get_widget_padding (priv->button, &button_padding); + 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_width (priv->box, &box_width, NULL); + xpad = button_padding.left + button_padding.right + padding.left + padding.right; - xpad = 2 * (border_width + focus_width + focus_pad) + - 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 { @@ -5338,9 +5534,6 @@ 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) @@ -5349,7 +5542,7 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, GtkBorder frame_padding; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); - get_widget_padding (priv->cell_view_frame, &frame_padding); + get_widget_padding_and_border (priv->cell_view_frame, &frame_padding); xpad = (2 * border_width) + frame_padding.left + frame_padding.right; minimum_width += xpad; @@ -5408,20 +5601,14 @@ 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 padding; - gtk_widget_style_get (GTK_WIDGET (widget), - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - NULL); - child = gtk_bin_get_child (GTK_BIN (widget)); - get_widget_padding (widget, &padding); + get_widget_padding_and_border (widget, &padding); size = avail_size; if (!priv->tree_view) @@ -5430,34 +5617,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; + gint box_width, box_height; + gint xpad, ypad; GtkBorder button_padding; - border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); - get_widget_padding (priv->button, &button_padding); + 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_padding.left + button_padding.right; - ypad = 2 * (border_width + focus_width + focus_pad) + - button_padding.top + button_padding.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; @@ -5497,14 +5677,13 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, gint border_width; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); - get_widget_padding (GTK_WIDGET (priv->cell_view_frame), &frame_padding); + get_widget_padding_and_border (GTK_WIDGET (priv->cell_view_frame), &frame_padding); 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