2 * Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "gtkcombobox.h"
21 #include "gtkcelllayout.h"
22 #include "gtkcellview.h"
23 #include "gtkcellviewmenuitem.h"
25 #include "gtktreeselection.h"
27 #include "gtktogglebutton.h"
28 #include "gtkvseparator.h"
32 #include "gtkeventbox.h"
33 #include "gtkcellrenderertext.h"
34 #include "gtkbindings.h"
35 #include "gtkliststore.h"
36 #include "gtkwindow.h"
38 #include <gdk/gdkkeysyms.h>
40 #include <gobject/gvaluecollector.h>
45 #include "gtkmarshalers.h"
49 /* WELCOME, to THE house of evil code */
52 typedef struct _ComboCellInfo ComboCellInfo;
55 GtkCellRenderer *cell;
58 GtkCellLayoutDataFunc func;
60 GDestroyNotify destroy;
66 #define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate))
68 struct _GtkComboBoxPrivate
80 GtkTreeViewColumn *column;
85 GtkWidget *cell_view_frame;
91 GtkWidget *popup_widget;
92 GtkWidget *popup_window;
93 GtkWidget *popup_frame;
103 guint popup_in_progress : 1;
115 PROP_ROW_SPAN_COLUMN,
116 PROP_COLUMN_SPAN_COLUMN,
120 static GtkBinClass *parent_class = NULL;
121 static guint combo_box_signals[LAST_SIGNAL] = {0,};
123 #define BONUS_PADDING 4
127 static void gtk_combo_box_class_init (GtkComboBoxClass *klass);
128 static void gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface);
129 static void gtk_combo_box_init (GtkComboBox *combo_box);
131 static void gtk_combo_box_set_property (GObject *object,
135 static void gtk_combo_box_get_property (GObject *object,
140 static void gtk_combo_box_style_set (GtkWidget *widget,
141 GtkStyle *previous_style,
143 static void gtk_combo_box_button_toggled (GtkWidget *widget,
145 static void gtk_combo_box_add (GtkContainer *container,
148 static ComboCellInfo *gtk_combo_box_get_cell_info (GtkComboBox *combo_box,
149 GtkCellRenderer *cell);
151 static void gtk_combo_box_menu_show (GtkWidget *menu,
153 static void gtk_combo_box_menu_hide (GtkWidget *menu,
156 static void gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
158 static void gtk_combo_box_menu_position (GtkMenu *menu,
163 static void gtk_combo_box_popup (GtkComboBox *combo_box);
164 static void gtk_combo_box_popdown (GtkComboBox *combo_box);
166 static gint gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
168 static void gtk_combo_box_remeasure (GtkComboBox *combo_box);
170 static void gtk_combo_box_unset_model (GtkComboBox *combo_box);
171 static void gtk_combo_box_set_model_internal (GtkComboBox *combo_box);
173 static void gtk_combo_box_size_request (GtkWidget *widget,
174 GtkRequisition *requisition);
175 static void gtk_combo_box_size_allocate (GtkWidget *widget,
176 GtkAllocation *allocation);
177 static void gtk_combo_box_forall (GtkContainer *container,
178 gboolean include_internals,
179 GtkCallback callback,
180 gpointer callback_data);
181 static gboolean gtk_combo_box_expose_event (GtkWidget *widget,
182 GdkEventExpose *event);
183 static gboolean gtk_combo_box_scroll_event (GtkWidget *widget,
184 GdkEventScroll *event);
187 static void gtk_combo_box_list_setup (GtkComboBox *combo_box);
188 static void gtk_combo_box_list_destroy (GtkComboBox *combo_box);
190 static gboolean gtk_combo_box_list_button_released (GtkWidget *widget,
191 GdkEventButton *event,
193 static gboolean gtk_combo_box_list_key_press (GtkWidget *widget,
196 static gboolean gtk_combo_box_list_button_pressed (GtkWidget *widget,
197 GdkEventButton *event,
200 static void gtk_combo_box_list_row_changed (GtkTreeModel *model,
206 static void gtk_combo_box_menu_setup (GtkComboBox *combo_box,
207 gboolean add_childs);
208 static void gtk_combo_box_menu_fill (GtkComboBox *combo_box);
209 static void gtk_combo_box_menu_destroy (GtkComboBox *combo_box);
211 static void gtk_combo_box_item_get_size (GtkComboBox *combo_box,
215 static void gtk_combo_box_relayout_item (GtkComboBox *combo_box,
217 static void gtk_combo_box_relayout (GtkComboBox *combo_box);
219 static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget,
220 GdkEventButton *event,
222 static void gtk_combo_box_menu_item_activate (GtkWidget *item,
224 static void gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
228 static void gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
231 static void gtk_combo_box_menu_row_changed (GtkTreeModel *model,
237 static void gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout,
238 GtkCellRenderer *cell,
240 static void gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout,
241 GtkCellRenderer *cell,
243 static void gtk_combo_box_cell_layout_clear (GtkCellLayout *layout);
244 static void gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout,
245 GtkCellRenderer *cell,
246 const gchar *attribute,
248 static void gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout,
249 GtkCellRenderer *cell,
250 GtkCellLayoutDataFunc func,
252 GDestroyNotify destroy);
253 static void gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout,
254 GtkCellRenderer *cell);
258 gtk_combo_box_get_type (void)
260 static GType combo_box_type = 0;
264 static const GTypeInfo combo_box_info =
266 sizeof (GtkComboBoxClass),
267 NULL, /* base_init */
268 NULL, /* base_finalize */
269 (GClassInitFunc) gtk_combo_box_class_init,
270 NULL, /* class_finalize */
271 NULL, /* class_data */
272 sizeof (GtkComboBox),
274 (GInstanceInitFunc) gtk_combo_box_init
277 static const GInterfaceInfo cell_layout_info =
279 (GInterfaceInitFunc) gtk_combo_box_cell_layout_init,
284 combo_box_type = g_type_register_static (GTK_TYPE_BIN,
289 g_type_add_interface_static (combo_box_type,
290 GTK_TYPE_CELL_LAYOUT,
294 return combo_box_type;
299 gtk_combo_box_class_init (GtkComboBoxClass *klass)
301 GObjectClass *object_class;
302 GtkBindingSet *binding_set;
303 GtkContainerClass *container_class;
304 GtkWidgetClass *widget_class;
306 binding_set = gtk_binding_set_by_class (klass);
308 container_class = (GtkContainerClass *)klass;
309 container_class->forall = gtk_combo_box_forall;
310 container_class->add = gtk_combo_box_add;
312 widget_class = (GtkWidgetClass *)klass;
313 widget_class->size_allocate = gtk_combo_box_size_allocate;
314 widget_class->size_request = gtk_combo_box_size_request;
315 widget_class->expose_event = gtk_combo_box_expose_event;
316 widget_class->scroll_event = gtk_combo_box_scroll_event;
318 object_class = (GObjectClass *)klass;
319 object_class->set_property = gtk_combo_box_set_property;
320 object_class->get_property = gtk_combo_box_get_property;
322 parent_class = g_type_class_peek_parent (klass);
325 combo_box_signals[CHANGED] =
326 g_signal_new ("changed",
327 G_OBJECT_CLASS_TYPE (klass),
329 G_STRUCT_OFFSET (GtkComboBoxClass, changed),
331 g_cclosure_marshal_VOID__VOID,
335 g_object_class_install_property (object_class,
337 g_param_spec_object ("model",
339 _("The model for the combo box"),
343 g_object_class_install_property (object_class,
345 g_param_spec_int ("wrap_width",
347 _("Wrap width for layouting the items in a grid"),
353 g_object_class_install_property (object_class,
354 PROP_ROW_SPAN_COLUMN,
355 g_param_spec_int ("row_span_column",
356 _("Row span column"),
357 _("TreeModel column containing the row span values"),
363 g_object_class_install_property (object_class,
364 PROP_COLUMN_SPAN_COLUMN,
365 g_param_spec_int ("column_span_column",
366 _("Column span column"),
367 _("TreeModel column containing the column span values"),
373 g_object_class_install_property (object_class,
375 g_param_spec_int ("active",
377 _("The item which is currently active"),
383 gtk_widget_class_install_style_property (widget_class,
384 g_param_spec_boolean ("appearance",
385 _("ComboBox appareance"),
386 _("ComboBox appearance, where TRUE means Windows-style."),
390 g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
394 gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
396 iface->pack_start = gtk_combo_box_cell_layout_pack_start;
397 iface->pack_end = gtk_combo_box_cell_layout_pack_end;
398 iface->clear = gtk_combo_box_cell_layout_clear;
399 iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
400 iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
401 iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
405 gtk_combo_box_init (GtkComboBox *combo_box)
407 combo_box->priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
409 g_signal_connect (combo_box, "style_set",
410 G_CALLBACK (gtk_combo_box_style_set), NULL);
412 combo_box->priv->cell_view = gtk_cell_view_new ();
413 gtk_container_add (GTK_CONTAINER (combo_box), combo_box->priv->cell_view);
414 gtk_widget_show (combo_box->priv->cell_view);
416 combo_box->priv->width = 0;
417 combo_box->priv->wrap_width = 0;
419 combo_box->priv->active_item = -1;
420 combo_box->priv->col_column = -1;
421 combo_box->priv->row_column = -1;
425 gtk_combo_box_set_property (GObject *object,
430 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
435 gtk_combo_box_set_model (combo_box, g_value_get_object (value));
438 case PROP_WRAP_WIDTH:
439 gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
442 case PROP_ROW_SPAN_COLUMN:
443 gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
446 case PROP_COLUMN_SPAN_COLUMN:
447 gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
451 gtk_combo_box_set_active (combo_box, g_value_get_int (value));
460 gtk_combo_box_get_property (GObject *object,
465 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
470 g_value_set_object (value, combo_box->priv->model);
473 case PROP_WRAP_WIDTH:
474 g_value_set_int (value, combo_box->priv->wrap_width);
477 case PROP_ROW_SPAN_COLUMN:
478 g_value_set_int (value, combo_box->priv->row_column);
481 case PROP_COLUMN_SPAN_COLUMN:
482 g_value_set_int (value, combo_box->priv->col_column);
486 g_value_set_int (value, gtk_combo_box_get_active (combo_box));
490 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
496 gtk_combo_box_style_set (GtkWidget *widget,
497 GtkStyle *previous_style,
501 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
503 gtk_widget_queue_resize (widget);
505 /* if wrap_width > 0, then we are in grid-mode and forced to use
508 if (combo_box->priv->wrap_width)
511 gtk_widget_style_get (widget,
512 "appearance", &appearance,
515 /* TRUE is windows style */
518 if (GTK_IS_MENU (combo_box->priv->popup_widget))
519 gtk_combo_box_menu_destroy (combo_box);
520 gtk_combo_box_list_setup (combo_box);
524 if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
525 gtk_combo_box_list_destroy (combo_box);
526 gtk_combo_box_menu_setup (combo_box, TRUE);
531 gtk_combo_box_button_toggled (GtkWidget *widget,
534 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
536 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
538 if (!combo_box->priv->popup_in_progress)
539 gtk_combo_box_popup (combo_box);
542 gtk_combo_box_popdown (combo_box);
546 gtk_combo_box_add (GtkContainer *container,
549 GtkComboBox *combo_box = GTK_COMBO_BOX (container);
551 if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent)
553 gtk_container_remove (container, combo_box->priv->cell_view);
554 (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
558 (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
561 if (combo_box->priv->cell_view &&
562 widget != combo_box->priv->cell_view)
564 /* since the cell_view was unparented, it's gone now */
565 combo_box->priv->cell_view = NULL;
567 if (!combo_box->priv->tree_view && combo_box->priv->separator)
569 gtk_widget_unparent (combo_box->priv->separator);
571 g_object_ref (G_OBJECT (combo_box->priv->arrow));
572 gtk_widget_unparent (combo_box->priv->arrow);
573 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
574 combo_box->priv->arrow);
575 g_object_unref (G_OBJECT (combo_box->priv->arrow));
577 gtk_widget_queue_resize (GTK_WIDGET (container));
579 else if (combo_box->priv->cell_view_frame)
581 gtk_widget_unparent (combo_box->priv->cell_view_frame);
582 combo_box->priv->cell_view_frame = NULL;
587 static ComboCellInfo *
588 gtk_combo_box_get_cell_info (GtkComboBox *combo_box,
589 GtkCellRenderer *cell)
593 for (i = combo_box->priv->cells; i; i = i->next)
595 ComboCellInfo *info = (ComboCellInfo *)i->data;
597 if (info->cell == cell)
605 gtk_combo_box_menu_show (GtkWidget *menu,
608 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
610 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
612 combo_box->priv->popup_in_progress = FALSE;
616 gtk_combo_box_menu_hide (GtkWidget *menu,
619 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
621 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
626 gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
629 if (GTK_IS_MENU (combo_box->priv->popup_widget))
630 combo_box->priv->popup_widget = NULL;
631 else if (combo_box->priv->popup_widget)
633 gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame),
634 combo_box->priv->popup_widget);
635 g_object_unref (G_OBJECT (combo_box->priv->popup_widget));
636 combo_box->priv->popup_widget = NULL;
639 if (GTK_IS_MENU (popup))
641 if (combo_box->priv->popup_window)
643 gtk_widget_destroy (combo_box->priv->popup_window);
644 combo_box->priv->popup_window = combo_box->priv->popup_frame = NULL;
647 combo_box->priv->popup_widget = popup;
649 g_signal_connect (popup, "show",
650 G_CALLBACK (gtk_combo_box_menu_show), combo_box);
651 g_signal_connect (popup, "hide",
652 G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
654 /* FIXME: need to attach to widget? */
658 if (!combo_box->priv->popup_window)
660 combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
662 combo_box->priv->popup_frame = gtk_frame_new (NULL);
663 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame),
665 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window),
666 combo_box->priv->popup_frame);
667 gtk_widget_show (combo_box->priv->popup_frame);
670 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame),
672 gtk_widget_show (popup);
673 g_object_ref (G_OBJECT (popup));
674 combo_box->priv->popup_widget = popup;
679 gtk_combo_box_menu_position (GtkMenu *menu,
688 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
690 /* FIXME: is using the size request here broken? */
691 child = GTK_BIN (combo_box)->child;
693 gdk_window_get_origin (child->window, &sx, &sy);
695 gtk_widget_size_request (GTK_WIDGET (menu), &req);
697 *x = sx + child->allocation.width - req.width;
698 *y = sy + child->allocation.height;
700 if (GTK_WIDGET_NO_WINDOW (child))
702 *x += child->allocation.x;
703 *y += child->allocation.y;
710 gtk_combo_box_popup (GtkComboBox *combo_box)
712 gint x, y, width, height;
715 if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
718 if (GTK_IS_MENU (combo_box->priv->popup_widget))
720 if (combo_box->priv->active_item != -1)
724 childs = gtk_container_get_children (GTK_CONTAINER (combo_box->priv->popup_widget));
725 gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
726 g_list_nth_data (childs, combo_box->priv->active_item));
727 g_list_free (childs);
730 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
732 gtk_combo_box_menu_position, combo_box,
738 sample = GTK_BIN (combo_box)->child;
740 width = sample->allocation.width;
741 height = sample->allocation.height;
743 gdk_window_get_origin (sample->window,
745 gtk_widget_set_size_request (combo_box->priv->popup_window,
748 if (GTK_WIDGET_NO_WINDOW (sample))
750 x += sample->allocation.x;
751 y += sample->allocation.y;
754 gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window),
758 gtk_widget_show_all (combo_box->priv->popup_window);
760 gtk_widget_grab_focus (combo_box->priv->popup_window);
761 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
764 if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view))
766 gdk_keyboard_grab (combo_box->priv->popup_window->window,
767 FALSE, GDK_CURRENT_TIME);
768 gtk_widget_grab_focus (combo_box->priv->tree_view);
773 gtk_combo_box_popdown (GtkComboBox *combo_box)
775 if (GTK_IS_MENU (combo_box->priv->popup_widget))
777 gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget));
781 gtk_widget_hide_all (combo_box->priv->popup_window);
782 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
787 gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
793 if (combo_box->priv->cell_view)
794 gtk_widget_style_get (combo_box->priv->cell_view,
795 "focus-line-width", &padding,
800 /* add some pixels for good measure */
801 padding += BONUS_PADDING;
803 if (combo_box->priv->cell_view)
804 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
809 return req.width + padding;
813 gtk_combo_box_remeasure (GtkComboBox *combo_box)
819 if (!gtk_tree_model_get_iter_first (combo_box->priv->model, &iter))
822 combo_box->priv->width = 0;
824 path = gtk_tree_path_new_from_indices (0, -1);
826 if (combo_box->priv->cell_view)
827 gtk_widget_style_get (combo_box->priv->cell_view,
828 "focus-line-width", &padding,
833 /* add some pixels for good measure */
834 padding += BONUS_PADDING;
840 if (combo_box->priv->cell_view)
841 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
846 combo_box->priv->width = MAX (combo_box->priv->width,
847 req.width + padding);
849 gtk_tree_path_next (path);
851 while (gtk_tree_model_iter_next (combo_box->priv->model, &iter));
853 gtk_tree_path_free (path);
857 gtk_combo_box_size_request (GtkWidget *widget,
858 GtkRequisition *requisition)
861 GtkRequisition bin_req;
863 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
866 gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
867 gtk_combo_box_remeasure (combo_box);
868 bin_req.width = MAX (bin_req.width, combo_box->priv->width);
870 if (!combo_box->priv->tree_view)
874 if (combo_box->priv->cell_view)
876 GtkRequisition sep_req, arrow_req;
877 gint border_width, xthickness, ythickness;
879 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
880 xthickness = combo_box->priv->button->style->xthickness;
881 ythickness = combo_box->priv->button->style->ythickness;
883 bin_req.width = MAX (bin_req.width, combo_box->priv->width);
885 gtk_widget_size_request (combo_box->priv->separator, &sep_req);
886 gtk_widget_size_request (combo_box->priv->arrow, &arrow_req);
888 height = MAX (sep_req.height, arrow_req.height);
889 height = MAX (height, bin_req.height);
891 width = bin_req.width + sep_req.width + arrow_req.width;
893 height += border_width + 1 + xthickness * 2 + 4;
894 width += border_width + 1 + ythickness * 2 + 4;
896 requisition->width = width;
897 requisition->height = height;
901 GtkRequisition but_req;
903 gtk_widget_size_request (combo_box->priv->button, &but_req);
905 requisition->width = bin_req.width + but_req.width;
906 requisition->height = MAX (bin_req.height, but_req.height);
912 GtkRequisition button_req;
915 *requisition = bin_req;
917 if (combo_box->priv->cell_view_frame)
919 requisition->width += 2 *
920 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
921 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
922 requisition->height += 2 *
923 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
924 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
928 gtk_widget_size_request (combo_box->priv->button, &button_req);
930 requisition->height = MAX (requisition->height, button_req.height);
931 requisition->width += button_req.width;
936 gtk_combo_box_size_allocate (GtkWidget *widget,
937 GtkAllocation *allocation)
939 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
943 widget->allocation = *allocation;
945 if (!combo_box->priv->tree_view)
947 if (combo_box->priv->cell_view)
949 gint border_width, xthickness, ythickness;
953 gtk_widget_size_allocate (combo_box->priv->button, allocation);
955 /* set some things ready */
956 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
957 xthickness = combo_box->priv->button->style->xthickness;
958 ythickness = combo_box->priv->button->style->ythickness;
960 child.x = allocation->x + border_width + 1 + xthickness + 2;
961 child.y = allocation->y + border_width + 1 + ythickness + 2;
963 width = allocation->width - (border_width + 1 + ythickness * 2 + 4);
965 /* handle the childs */
966 gtk_widget_size_request (combo_box->priv->arrow, &req);
967 child.width = req.width;
968 child.height = allocation->height - 2 * (child.y - allocation->y);
969 child.x += width - req.width;
970 gtk_widget_size_allocate (combo_box->priv->arrow, &child);
972 gtk_widget_size_request (combo_box->priv->separator, &req);
973 child.width = req.width;
974 child.x -= req.width;
975 gtk_widget_size_allocate (combo_box->priv->separator, &child);
977 child.width = child.x;
978 child.x = allocation->x + border_width + 1 + xthickness + 2;
979 child.width -= child.x;
981 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
985 gtk_widget_size_request (combo_box->priv->button, &req);
986 child.x = allocation->x + allocation->width - req.width;
987 child.y = allocation->y;
988 child.width = req.width;
989 child.height = allocation->height;
990 gtk_widget_size_allocate (combo_box->priv->button, &child);
992 child.x = allocation->x;
993 child.y = allocation->y;
994 child.width = allocation->width - req.width;
995 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
1003 gtk_widget_size_request (combo_box->priv->button, &req);
1004 child.x = allocation->x + allocation->width - req.width;
1005 child.y = allocation->y;
1006 child.width = req.width;
1007 child.height = allocation->height;
1008 gtk_widget_size_allocate (combo_box->priv->button, &child);
1011 child.x = allocation->x;
1012 child.y = allocation->y;
1013 child.width = allocation->width - req.width;
1014 child.height = allocation->height;
1016 if (combo_box->priv->cell_view_frame)
1018 gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child);
1022 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1023 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
1025 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1026 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
1027 child.width -= 2 * (
1028 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1029 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
1030 child.height -= 2 * (
1031 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1032 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
1035 gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
1040 gtk_combo_box_unset_model (GtkComboBox *combo_box)
1042 if (!combo_box->priv->tree_view)
1045 g_signal_handler_disconnect (combo_box->priv->model,
1046 combo_box->priv->inserted_id);
1047 g_signal_handler_disconnect (combo_box->priv->model,
1048 combo_box->priv->deleted_id);
1049 g_signal_handler_disconnect (combo_box->priv->model,
1050 combo_box->priv->changed_id);
1052 combo_box->priv->inserted_id =
1053 combo_box->priv->deleted_id =
1054 combo_box->priv->changed_id = -1;
1056 if (combo_box->priv->popup_widget)
1057 gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget),
1058 (GtkCallback)gtk_widget_destroy, NULL);
1063 g_signal_handler_disconnect (combo_box->priv->model,
1064 combo_box->priv->changed_id);
1065 combo_box->priv->changed_id = -1;
1070 gtk_combo_box_set_model_internal (GtkComboBox *combo_box)
1072 if (!combo_box->priv->tree_view)
1075 combo_box->priv->inserted_id =
1076 g_signal_connect (combo_box->priv->model, "row_inserted",
1077 G_CALLBACK (gtk_combo_box_menu_row_inserted),
1079 combo_box->priv->deleted_id =
1080 g_signal_connect (combo_box->priv->model, "row_deleted",
1081 G_CALLBACK (gtk_combo_box_menu_row_deleted),
1083 combo_box->priv->changed_id =
1084 g_signal_connect (combo_box->priv->model, "row_changed",
1085 G_CALLBACK (gtk_combo_box_menu_row_changed),
1091 gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
1092 combo_box->priv->model);
1094 combo_box->priv->changed_id =
1095 g_signal_connect (combo_box->priv->model, "row_changed",
1096 G_CALLBACK (gtk_combo_box_list_row_changed),
1102 gtk_combo_box_forall (GtkContainer *container,
1103 gboolean include_internals,
1104 GtkCallback callback,
1105 gpointer callback_data)
1107 GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1109 if (include_internals)
1111 if (!combo_box->priv->tree_view)
1113 if (combo_box->priv->cell_view && combo_box->priv->button)
1115 (* callback) (combo_box->priv->button, callback_data);
1116 (* callback) (combo_box->priv->separator, callback_data);
1117 (* callback) (combo_box->priv->arrow, callback_data);
1119 else if (combo_box->priv->arrow)
1121 (* callback) (combo_box->priv->button, callback_data);
1122 (* callback) (combo_box->priv->arrow, callback_data);
1127 (* callback) (combo_box->priv->button, callback_data);
1128 if (combo_box->priv->cell_view_frame)
1129 (* callback) (combo_box->priv->cell_view_frame, callback_data);
1133 if (GTK_BIN (container)->child)
1134 (* callback) (GTK_BIN (container)->child, callback_data);
1138 gtk_combo_box_expose_event (GtkWidget *widget,
1139 GdkEventExpose *event)
1141 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1143 if (!combo_box->priv->tree_view)
1145 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1146 combo_box->priv->button, event);
1148 if (combo_box->priv->separator)
1150 gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1151 combo_box->priv->separator, event);
1153 /* if not in this case, arrow gets its expose event from button */
1154 gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1155 combo_box->priv->arrow, event);
1160 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1161 combo_box->priv->button, event);
1163 if (combo_box->priv->cell_view_frame)
1164 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1165 combo_box->priv->cell_view_frame, event);
1168 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1169 GTK_BIN (widget)->child, event);
1175 gtk_combo_box_scroll_event (GtkWidget *widget,
1176 GdkEventScroll *event)
1178 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1182 index = gtk_combo_box_get_active (combo_box);
1186 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1188 if (event->direction == GDK_SCROLL_UP)
1193 gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
1204 cell_view_sync_cells (GtkComboBox *combo_box,
1205 GtkCellView *cell_view)
1209 for (k = combo_box->priv->cells; k; k = k->next)
1212 ComboCellInfo *info = (ComboCellInfo *)k->data;
1214 if (info->pack == GTK_PACK_START)
1215 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view),
1216 info->cell, info->expand);
1217 else if (info->pack == GTK_PACK_END)
1218 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view),
1219 info->cell, info->expand);
1221 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view),
1223 info->func, info->func_data, NULL);
1225 for (j = info->attributes; j; j = j->next->next)
1227 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view),
1230 GPOINTER_TO_INT (j->next->data));
1236 gtk_combo_box_menu_setup (GtkComboBox *combo_box,
1237 gboolean add_childs)
1241 if (combo_box->priv->cell_view)
1243 combo_box->priv->button = gtk_toggle_button_new ();
1244 g_signal_connect (combo_box->priv->button, "toggled",
1245 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1246 gtk_widget_set_parent (combo_box->priv->button,
1247 GTK_BIN (combo_box)->child->parent);
1249 combo_box->priv->separator = gtk_vseparator_new ();
1250 gtk_widget_set_parent (combo_box->priv->separator,
1251 combo_box->priv->button);
1252 gtk_widget_show (combo_box->priv->separator);
1254 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1255 gtk_widget_set_parent (combo_box->priv->arrow, combo_box->priv->button);
1256 gtk_widget_show (combo_box->priv->arrow);
1258 gtk_widget_show_all (combo_box->priv->button);
1260 if (GTK_WIDGET_MAPPED (GTK_BIN (combo_box)->child))
1262 /* I have no clue why, but we need to manually map in this case. */
1263 gtk_widget_map (combo_box->priv->separator);
1264 gtk_widget_map (combo_box->priv->arrow);
1269 combo_box->priv->button = gtk_toggle_button_new ();
1270 g_signal_connect (combo_box->priv->button, "toggled",
1271 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1272 gtk_widget_set_parent (combo_box->priv->button,
1273 GTK_BIN (combo_box)->child->parent);
1275 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1276 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1277 combo_box->priv->arrow);
1278 gtk_widget_show_all (combo_box->priv->button);
1281 g_signal_connect (combo_box->priv->button, "button_press_event",
1282 G_CALLBACK (gtk_combo_box_menu_button_press),
1285 /* create our funky menu */
1286 box = gtk_menu_new ();
1287 gtk_combo_box_set_popup_widget (combo_box, box);
1291 gtk_combo_box_menu_fill (combo_box);
1295 gtk_combo_box_menu_fill (GtkComboBox *combo_box)
1301 if (!combo_box->priv->model)
1304 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1305 menu = combo_box->priv->popup_widget;
1307 for (i = 0; i < items; i++)
1311 path = gtk_tree_path_new_from_indices (i, -1);
1312 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1314 g_signal_connect (tmp, "activate",
1315 G_CALLBACK (gtk_combo_box_menu_item_activate),
1318 cell_view_sync_cells (combo_box,
1319 GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1321 gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp);
1322 gtk_widget_show (tmp);
1324 gtk_tree_path_free (path);
1329 gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
1331 /* disconnect signal handlers */
1332 gtk_combo_box_unset_model (combo_box);
1334 g_signal_handlers_disconnect_matched (combo_box->priv->button,
1335 G_SIGNAL_MATCH_DATA,
1337 gtk_combo_box_menu_button_press, NULL);
1339 /* unparent will remove our latest ref */
1340 if (combo_box->priv->cell_view)
1342 gtk_widget_unparent (combo_box->priv->arrow);
1343 gtk_widget_unparent (combo_box->priv->separator);
1344 gtk_widget_unparent (combo_box->priv->button);
1348 /* will destroy the arrow too */
1349 gtk_widget_unparent (combo_box->priv->button);
1352 /* changing the popup window will unref the menu and the childs */
1360 gtk_combo_box_item_get_size (GtkComboBox *combo_box,
1367 gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index);
1371 if (combo_box->priv->col_column == -1)
1374 gtk_tree_model_get (combo_box->priv->model, &iter,
1375 combo_box->priv->col_column, cols,
1381 if (combo_box->priv->row_column == -1)
1384 gtk_tree_model_get (combo_box->priv->model, &iter,
1385 combo_box->priv->row_column, rows,
1391 menu_occupied (GtkMenu *menu,
1395 guint bottom_attach)
1399 g_return_val_if_fail (GTK_IS_MENU (menu), TRUE);
1400 g_return_val_if_fail (left_attach < right_attach, TRUE);
1401 g_return_val_if_fail (top_attach < bottom_attach, TRUE);
1403 for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
1406 gboolean h_intersect = FALSE;
1407 gboolean v_intersect = FALSE;
1409 gtk_container_child_get (GTK_CONTAINER (menu), i->data,
1412 "bottom_attach", &b,
1416 /* look if this item intersects with the given coordinates */
1417 h_intersect = left_attach <= l && l <= right_attach;
1418 h_intersect &= left_attach <= r && r <= right_attach;
1420 v_intersect = top_attach <= t && t <= bottom_attach;
1421 v_intersect &= top_attach <= b && b <= bottom_attach;
1423 if (h_intersect && v_intersect)
1431 gtk_combo_box_relayout_item (GtkComboBox *combo_box,
1434 gint current_col = 0, current_row = 0;
1440 menu = combo_box->priv->popup_widget;
1441 if (!GTK_IS_MENU_SHELL (menu))
1444 list = gtk_container_get_children (GTK_CONTAINER (menu));
1445 item = g_list_nth_data (list, index);
1447 gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
1449 /* look for a good spot */
1452 if (current_col + cols > combo_box->priv->wrap_width)
1458 if (!menu_occupied (GTK_MENU (menu),
1459 current_col, current_col + cols,
1460 current_row, current_row + rows))
1466 /* set attach props */
1467 gtk_menu_attach (GTK_MENU (menu), item,
1468 current_col, current_col + cols,
1469 current_row, current_row + rows);
1473 gtk_combo_box_relayout (GtkComboBox *combo_box)
1479 /* ensure we are in menu style */
1480 if (combo_box->priv->tree_view)
1481 gtk_combo_box_list_destroy (combo_box);
1483 menu = combo_box->priv->popup_widget;
1485 if (!GTK_IS_MENU_SHELL (menu))
1487 gtk_combo_box_menu_setup (combo_box, FALSE);
1488 menu = combo_box->priv->popup_widget;
1491 /* get rid of all children */
1492 g_return_if_fail (GTK_IS_MENU_SHELL (menu));
1494 list = gtk_container_get_children (GTK_CONTAINER (menu));
1496 for (j = g_list_last (list); j; j = j->prev)
1497 gtk_container_remove (GTK_CONTAINER (menu), j->data);
1502 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1504 for (i = 0; i < items; i++)
1509 path = gtk_tree_path_new_from_indices (i, -1);
1510 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1513 g_signal_connect (tmp, "activate",
1514 G_CALLBACK (gtk_combo_box_menu_item_activate),
1517 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1519 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), tmp, i);
1521 if (combo_box->priv->wrap_width)
1522 gtk_combo_box_relayout_item (combo_box, i);
1524 gtk_widget_show (tmp);
1526 gtk_tree_path_free (path);
1532 gtk_combo_box_menu_button_press (GtkWidget *widget,
1533 GdkEventButton *event,
1536 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1538 if (! GTK_IS_MENU (combo_box->priv->popup_widget))
1541 if (event->type == GDK_BUTTON_PRESS && event->button == 1)
1543 combo_box->priv->popup_in_progress = TRUE;
1544 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
1546 gtk_combo_box_menu_position, combo_box,
1547 event->button, event->time);
1556 gtk_combo_box_menu_item_activate (GtkWidget *item,
1561 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1563 menu = combo_box->priv->popup_widget;
1564 g_return_if_fail (GTK_IS_MENU (menu));
1566 index = g_list_index (GTK_MENU_SHELL (menu)->children, item);
1568 gtk_combo_box_set_active (combo_box, index);
1572 gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
1579 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1581 if (!combo_box->priv->popup_widget)
1584 menu = combo_box->priv->popup_widget;
1585 g_return_if_fail (GTK_IS_MENU (menu));
1587 item = gtk_cell_view_menu_item_new_from_model (model, path);
1588 g_signal_connect (item, "activate",
1589 G_CALLBACK (gtk_combo_box_menu_item_activate),
1592 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child));
1594 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item,
1595 gtk_tree_path_get_indices (path)[0]);
1596 gtk_widget_show (item);
1600 gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
1607 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1609 if (!combo_box->priv->popup_widget)
1612 index = gtk_tree_path_get_indices (path)[0];
1613 items = gtk_tree_model_iter_n_children (model, NULL);
1615 if (gtk_combo_box_get_active (combo_box) == index)
1616 gtk_combo_box_set_active (combo_box, index + 1 % items);
1618 menu = combo_box->priv->popup_widget;
1619 g_return_if_fail (GTK_IS_MENU (menu));
1621 item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index);
1622 g_return_if_fail (GTK_IS_MENU_ITEM (item));
1624 gtk_container_remove (GTK_CONTAINER (menu), item);
1628 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
1633 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1636 if (!combo_box->priv->popup_widget)
1639 if (combo_box->priv->wrap_width)
1640 gtk_combo_box_relayout_item (combo_box,
1641 gtk_tree_path_get_indices (path)[0]);
1643 width = gtk_combo_box_calc_requested_width (combo_box, path);
1645 if (width > combo_box->priv->width)
1647 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
1648 gtk_widget_queue_resize (combo_box->priv->cell_view);
1649 combo_box->priv->width = width;
1658 gtk_combo_box_list_setup (GtkComboBox *combo_box)
1661 GtkTreeSelection *sel;
1663 combo_box->priv->button = gtk_toggle_button_new ();
1664 gtk_widget_set_parent (combo_box->priv->button,
1665 GTK_BIN (combo_box)->child->parent);
1666 g_signal_connect (combo_box->priv->button, "button_press_event",
1667 G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
1668 g_signal_connect (combo_box->priv->button, "toggled",
1669 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1671 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1672 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1673 combo_box->priv->arrow);
1674 gtk_widget_show_all (combo_box->priv->button);
1676 if (combo_box->priv->cell_view)
1678 combo_box->priv->cell_view_frame = gtk_frame_new (NULL);
1679 gtk_widget_set_parent (combo_box->priv->cell_view_frame,
1680 GTK_BIN (combo_box)->child->parent);
1681 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
1684 g_object_set (G_OBJECT (combo_box->priv->cell_view),
1685 "background", "white",
1686 "background_set", TRUE,
1689 gtk_widget_show (combo_box->priv->cell_view_frame);
1692 combo_box->priv->tree_view = gtk_tree_view_new ();
1693 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1694 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1695 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view),
1698 g_signal_connect (combo_box->priv->tree_view, "button_press_event",
1699 G_CALLBACK (gtk_combo_box_list_button_pressed),
1701 g_signal_connect (combo_box->priv->tree_view, "button_release_event",
1702 G_CALLBACK (gtk_combo_box_list_button_released),
1704 g_signal_connect (combo_box->priv->tree_view, "key_press_event",
1705 G_CALLBACK (gtk_combo_box_list_key_press),
1708 combo_box->priv->column = gtk_tree_view_column_new ();
1709 gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view),
1710 combo_box->priv->column);
1712 /* set the models */
1713 gtk_combo_box_set_model_internal (combo_box);
1716 for (i = combo_box->priv->cells; i; i = i->next)
1719 ComboCellInfo *info = (ComboCellInfo *)i->data;
1721 if (info->pack == GTK_PACK_START)
1722 gtk_tree_view_column_pack_start (combo_box->priv->column,
1723 info->cell, info->expand);
1724 else if (info->pack == GTK_PACK_END)
1725 gtk_tree_view_column_pack_end (combo_box->priv->column,
1726 info->cell, info->expand);
1728 for (j = info->attributes; j; j = j->next->next)
1730 gtk_tree_view_column_add_attribute (combo_box->priv->column,
1733 GPOINTER_TO_INT (j->next->data));
1737 if (combo_box->priv->active_item != -1)
1741 path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1);
1744 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view),
1746 gtk_tree_path_free (path);
1750 /* set sample/popup widgets */
1751 gtk_combo_box_set_popup_widget (GTK_COMBO_BOX (combo_box),
1752 combo_box->priv->tree_view);
1754 gtk_widget_show (combo_box->priv->tree_view);
1758 gtk_combo_box_list_destroy (GtkComboBox *combo_box)
1760 /* disconnect signals */
1761 gtk_combo_box_unset_model (combo_box);
1763 g_signal_handlers_disconnect_matched (combo_box->priv->tree_view,
1764 G_SIGNAL_MATCH_DATA,
1765 0, 0, NULL, NULL, combo_box);
1766 g_signal_handlers_disconnect_matched (combo_box->priv->button,
1767 G_SIGNAL_MATCH_DATA,
1769 gtk_combo_box_list_button_pressed,
1772 /* destroy things (unparent will kill the latest ref from us)
1773 * last unref on button will destroy the arrow
1775 gtk_widget_unparent (combo_box->priv->button);
1777 if (combo_box->priv->cell_view)
1779 g_object_set (G_OBJECT (combo_box->priv->cell_view),
1780 "background_set", FALSE,
1783 gtk_widget_unparent (combo_box->priv->cell_view_frame);
1786 gtk_widget_destroy (combo_box->priv->tree_view);
1787 combo_box->priv->tree_view = NULL;
1788 combo_box->priv->popup_widget = NULL;
1793 gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box)
1795 if (GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view))
1796 gtk_grab_remove (combo_box->priv->tree_view);
1798 if (GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window))
1800 gtk_grab_remove (combo_box->priv->popup_window);
1801 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1806 gtk_combo_box_list_button_pressed (GtkWidget *widget,
1807 GdkEventButton *event,
1810 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1812 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1814 if (ewidget == combo_box->priv->tree_view)
1817 if ((ewidget != combo_box->priv->button) ||
1818 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1821 gtk_combo_box_popup (combo_box);
1823 gtk_grab_add (combo_box->priv->popup_window);
1824 gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE,
1825 GDK_BUTTON_PRESS_MASK |
1826 GDK_BUTTON_RELEASE_MASK |
1827 GDK_POINTER_MOTION_MASK,
1828 NULL, NULL, GDK_CURRENT_TIME);
1830 gtk_grab_add (combo_box->priv->tree_view);
1832 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
1835 combo_box->priv->popup_in_progress = TRUE;
1841 gtk_combo_box_list_button_released (GtkWidget *widget,
1842 GdkEventButton *event,
1846 GtkTreePath *path = NULL;
1848 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1850 gboolean popup_in_progress = FALSE;
1852 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1854 if (combo_box->priv->popup_in_progress)
1856 popup_in_progress = TRUE;
1857 combo_box->priv->popup_in_progress = FALSE;
1860 if (ewidget != combo_box->priv->tree_view)
1862 if (ewidget == combo_box->priv->button &&
1863 !popup_in_progress &&
1864 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1866 gtk_combo_box_list_remove_grabs (combo_box);
1867 gtk_combo_box_popdown (combo_box);
1871 /* released outside treeview */
1872 if (ewidget != combo_box->priv->button)
1874 gtk_combo_box_list_remove_grabs (combo_box);
1875 gtk_combo_box_popdown (combo_box);
1884 gtk_combo_box_list_remove_grabs (combo_box);
1886 /* select something cool */
1887 ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
1893 return TRUE; /* clicked outside window? */
1895 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1896 gtk_combo_box_popdown (combo_box);
1898 gtk_tree_path_free (path);
1904 gtk_combo_box_list_key_press (GtkWidget *widget,
1908 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1910 if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
1911 event->keyval == GDK_space || event->keyval == GDK_KP_Space) ||
1912 event->keyval == GDK_Escape)
1914 if (event->keyval != GDK_Escape)
1918 GtkTreeModel *model = NULL;
1919 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1921 ret = gtk_tree_selection_get_selected (sel, &model, &iter);
1926 path = gtk_tree_model_get_path (model, &iter);
1929 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1930 gtk_tree_path_free (path);
1935 /* reset active item -- this is incredibly lame and ugly */
1936 gtk_combo_box_set_active (combo_box,
1937 gtk_combo_box_get_active (combo_box));
1939 gtk_combo_box_list_remove_grabs (combo_box);
1940 gtk_combo_box_popdown (combo_box);
1949 gtk_combo_box_list_row_changed (GtkTreeModel *model,
1954 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1957 width = gtk_combo_box_calc_requested_width (combo_box, path);
1959 if (width > combo_box->priv->width)
1961 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
1962 gtk_widget_queue_resize (combo_box->priv->cell_view);
1963 combo_box->priv->width = width;
1968 * GtkCellLayout implementation
1971 gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout,
1972 GtkCellRenderer *cell,
1975 ComboCellInfo *info;
1976 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
1979 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
1980 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1982 info = g_new0 (ComboCellInfo, 1);
1984 info->expand = expand;
1985 info->pack = GTK_PACK_START;
1987 combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
1989 if (combo_box->priv->cell_view)
1990 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
1993 if (combo_box->priv->column)
1994 gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand);
1996 menu = combo_box->priv->popup_widget;
1997 if (GTK_IS_MENU (menu))
2001 list = gtk_container_get_children (GTK_CONTAINER (menu));
2002 for (i = list; i; i = i->next)
2006 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2007 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2009 view = GTK_CELL_VIEW (i->data);
2011 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand);
2018 gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout,
2019 GtkCellRenderer *cell,
2022 ComboCellInfo *info;
2023 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2026 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2027 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2029 info = g_new0 (ComboCellInfo, 1);
2031 info->expand = expand;
2032 info->pack = GTK_PACK_END;
2034 if (combo_box->priv->cell_view)
2035 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2038 if (combo_box->priv->column)
2039 gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand);
2041 menu = combo_box->priv->popup_widget;
2042 if (GTK_IS_MENU (menu))
2046 list = gtk_container_get_children (GTK_CONTAINER (menu));
2047 for (i = list; i; i = i->next)
2051 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2052 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2054 view = GTK_CELL_VIEW (i->data);
2056 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand);
2063 gtk_combo_box_cell_layout_clear (GtkCellLayout *layout)
2066 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2068 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2070 if (combo_box->priv->cell_view)
2071 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view));
2073 if (combo_box->priv->column)
2074 gtk_tree_view_column_clear (combo_box->priv->column);
2076 menu = combo_box->priv->popup_widget;
2077 if (GTK_IS_MENU (menu))
2081 list = gtk_container_get_children (GTK_CONTAINER (menu));
2082 for (i = list; i; i = i->next)
2086 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2087 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2089 view = GTK_CELL_VIEW (i->data);
2091 gtk_cell_layout_clear (GTK_CELL_LAYOUT (view));
2097 gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout,
2098 GtkCellRenderer *cell,
2099 const gchar *attribute,
2102 ComboCellInfo *info;
2103 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2106 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2107 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2109 info = gtk_combo_box_get_cell_info (combo_box, cell);
2111 info->attributes = g_slist_prepend (info->attributes,
2112 GINT_TO_POINTER (column));
2113 info->attributes = g_slist_prepend (info->attributes,
2114 g_strdup (attribute));
2116 if (combo_box->priv->cell_view)
2117 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2118 cell, attribute, column);
2120 if (combo_box->priv->column)
2121 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column),
2122 cell, attribute, column);
2124 menu = combo_box->priv->popup_widget;
2125 if (GTK_IS_MENU (menu))
2129 list = gtk_container_get_children (GTK_CONTAINER (menu));
2130 for (i = list; i; i = i->next)
2134 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2135 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2137 view = GTK_CELL_VIEW (i->data);
2139 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell,
2145 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2149 gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout,
2150 GtkCellRenderer *cell,
2151 GtkCellLayoutDataFunc func,
2153 GDestroyNotify destroy)
2155 ComboCellInfo *info;
2156 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2159 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2161 info = gtk_combo_box_get_cell_info (combo_box, cell);
2162 g_return_if_fail (info != NULL);
2166 GDestroyNotify d = info->destroy;
2168 info->destroy = NULL;
2169 d (info->func_data);
2173 info->func_data = func_data;
2174 info->destroy = destroy;
2176 if (combo_box->priv->cell_view)
2177 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL);
2179 if (combo_box->priv->column)
2180 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL);
2182 menu = combo_box->priv->popup_widget;
2183 if (GTK_IS_MENU (menu))
2187 list = gtk_container_get_children (GTK_CONTAINER (menu));
2188 for (i = list; i; i = i->next)
2192 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2193 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2195 view = GTK_CELL_VIEW (i->data);
2197 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell,
2198 func, func_data, NULL);
2203 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2207 gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout,
2208 GtkCellRenderer *cell)
2210 ComboCellInfo *info;
2211 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2215 g_return_if_fail (GTK_IS_COMBO_BOX (layout));
2216 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2218 info = gtk_combo_box_get_cell_info (combo_box, cell);
2219 g_return_if_fail (info != NULL);
2221 list = info->attributes;
2222 while (list && list->next)
2224 g_free (list->data);
2225 list = list->next->next;
2227 g_slist_free (list);
2229 info->attributes = NULL;
2231 if (combo_box->priv->cell_view)
2232 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell);
2234 if (combo_box->priv->column)
2235 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell);
2237 menu = combo_box->priv->popup_widget;
2238 if (GTK_IS_MENU (menu))
2242 list = gtk_container_get_children (GTK_CONTAINER (menu));
2243 for (i = list; i; i = i->next)
2247 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2248 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2250 view = GTK_CELL_VIEW (i->data);
2252 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell);
2257 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2265 * gtk_combo_box_new:
2267 * Creates a new empty #GtkComboBox.
2269 * Return value: A new #GtkComboBox.
2274 gtk_combo_box_new (void)
2276 return GTK_WIDGET (g_object_new (gtk_combo_box_get_type (), NULL));
2280 * gtk_combo_box_new_with_model:
2281 * @model: A #GtkTreeModel.
2283 * Creates a new #GtkComboBox with the model initialized to @model.
2285 * Return value: A new #GtkComboBox.
2290 gtk_combo_box_new_with_model (GtkTreeModel *model)
2292 GtkComboBox *combo_box;
2294 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
2296 combo_box = GTK_COMBO_BOX (g_object_new (gtk_combo_box_get_type (),
2300 return GTK_WIDGET (combo_box);
2304 * gtk_combo_box_set_wrap_width:
2305 * @combo_box: A #GtkComboBox.
2306 * @width: Preferred number of columns.
2308 * Sets the wrap width of @combo_box to be @width. The wrap width is basically
2309 * the preferred number of columns when you want to the popup to be layed out
2315 gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
2318 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2319 g_return_if_fail (width > 0);
2321 combo_box->priv->wrap_width = width;
2323 gtk_combo_box_relayout (combo_box);
2327 * gtk_combo_box_set_row_span_column:
2328 * @combo_box: A #GtkComboBox.
2329 * @row_span: A column in the model passed during construction.
2331 * Sets the column with row span information for @combo_box to be @row_span.
2332 * The row span column contains integers which indicate how many rows
2333 * an item should span.
2338 gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
2343 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2345 col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2346 g_return_if_fail (row_span >= 0 && row_span < col);
2348 combo_box->priv->row_column = row_span;
2350 gtk_combo_box_relayout (combo_box);
2354 * gtk_combo_box_set_column_span_column:
2355 * @combo_box: A #GtkComboBox.
2356 * @column_span: A column in the model passed during construction.
2358 * Sets the column with column span information for @combo_box to be
2359 * @column_span. The column span column contains integers which indicate
2360 * how many columns an item should span.
2365 gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
2370 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2372 col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2373 g_return_if_fail (column_span >= 0 && column_span < col);
2375 combo_box->priv->col_column = column_span;
2377 gtk_combo_box_relayout (combo_box);
2381 * gtk_combo_box_get_active:
2382 * @combo_box: A #GtkComboBox.
2384 * Returns the index of the currently active item, or -1 if there's no
2387 * Return value: An integer which is the index of the currently active item, or
2388 * -1 if there's no active item.
2393 gtk_combo_box_get_active (GtkComboBox *combo_box)
2395 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
2397 return combo_box->priv->active_item;
2401 * gtk_combo_box_set_active:
2402 * @combo_box: A #GtkComboBox.
2403 * @index: An index in the model passed during construction, or -1 to have
2406 * Sets the active item of @combo_box to be the item at @index.
2411 gtk_combo_box_set_active (GtkComboBox *combo_box,
2416 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2417 /* -1 means "no item selected" */
2418 g_return_if_fail (index >= -1);
2420 if (combo_box->priv->active_item == index)
2423 combo_box->priv->active_item = index;
2427 if (combo_box->priv->tree_view)
2428 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)));
2431 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2433 if (GTK_IS_MENU (menu))
2434 gtk_menu_set_active (menu, -1);
2437 if (combo_box->priv->cell_view)
2438 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
2442 path = gtk_tree_path_new_from_indices (index, -1);
2444 if (combo_box->priv->tree_view)
2445 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE);
2448 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2450 if (GTK_IS_MENU (menu))
2451 gtk_menu_set_active (GTK_MENU (menu), index);
2454 if (combo_box->priv->cell_view)
2455 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path);
2457 gtk_tree_path_free (path);
2460 g_signal_emit_by_name (combo_box, "changed", NULL, NULL);
2465 * gtk_combo_box_get_active_iter:
2466 * @combo_box: A #GtkComboBox
2467 * @iter: The uninitialized #GtkTreeIter.
2469 * Set @iter to point to the current active item, if it exists.
2471 * Return value: %TRUE, if @iter was set
2476 gtk_combo_box_get_active_iter (GtkComboBox *combo_box,
2483 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
2485 active = gtk_combo_box_get_active (combo_box);
2489 path = gtk_tree_path_new_from_indices (active, -1);
2490 retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box),
2492 gtk_tree_path_free (path);
2498 * gtk_combo_box_set_active_iter:
2499 * @combo_box: A #GtkComboBox
2500 * @iter: The #GtkTreeIter.
2502 * Sets the current active item to be the one referenced by @iter.
2507 gtk_combo_box_set_active_iter (GtkComboBox *combo_box,
2512 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2514 path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
2515 g_return_if_fail (path != NULL);
2516 g_return_if_fail (gtk_tree_path_get_depth (path) != 1);
2518 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
2519 gtk_tree_path_free (path);
2523 * gtk_combo_box_set_model:
2524 * @combo_box: A #GtkComboBox.
2525 * @model: A #GtkTreeModel.
2527 * Sets the model used by @combo_box to be @model. Will unset a
2528 * previously set model (if applicable).
2533 gtk_combo_box_set_model (GtkComboBox *combo_box,
2534 GtkTreeModel *model)
2536 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2537 g_return_if_fail (GTK_IS_TREE_MODEL (model));
2539 if (combo_box->priv->model)
2541 gtk_combo_box_unset_model (combo_box);
2542 g_object_unref (G_OBJECT (combo_box->priv->model));
2545 combo_box->priv->model = model;
2546 g_object_ref (G_OBJECT (combo_box->priv->model));
2548 gtk_combo_box_set_model_internal (combo_box);
2549 if (!combo_box->priv->tree_view && combo_box->priv->popup_widget)
2550 gtk_combo_box_menu_fill (combo_box);
2552 if (combo_box->priv->cell_view)
2553 gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
2554 combo_box->priv->model);
2558 * gtk_combo_box_get_model
2559 * @combo_box: A #GtkComboBox.
2561 * Returns the #GtkTreeModel which is acting as data source for @combo_box.
2563 * Return value: A #GtkTreeModel which was passed during construction.
2568 gtk_combo_box_get_model (GtkComboBox *combo_box)
2570 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
2572 return combo_box->priv->model;
2576 /* convenience API for simple text combos */
2579 * gtk_combo_box_new_text:
2581 * Convenience function which constructs a new text combo box, which is a
2582 * #GtkComboBox just displaying strings. If you use this function to create
2583 * a text combo box, you only want to manipulate it's data source with the
2584 * following convenience functions: gtk_combo_box_append_text(),
2585 * gtk_combo_box_insert_text() and gtk_combo_box_prepend_text().
2587 * Return value: A new text combo box.
2592 gtk_combo_box_new_text (void)
2594 GtkWidget *combo_box;
2595 GtkCellRenderer *cell;
2596 GtkListStore *store;
2598 store = gtk_list_store_new (1, G_TYPE_STRING);
2600 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
2602 cell = gtk_cell_renderer_text_new ();
2603 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
2604 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
2612 * gtk_combo_box_append_text:
2613 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2616 * Appends @string to the list of strings stored in @combo_box. Note that
2617 * you can only use this function with combo boxes constructed with
2618 * gtk_combo_box_new_text().
2623 gtk_combo_box_append_text (GtkComboBox *combo_box,
2627 GtkListStore *store;
2629 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2630 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2631 g_return_if_fail (text != NULL);
2633 store = GTK_LIST_STORE (combo_box->priv->model);
2635 gtk_list_store_append (store, &iter);
2636 gtk_list_store_set (store, &iter, 0, text, -1);
2640 * gtk_combo_box_insert_text:
2641 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2642 * @position: An index to insert @text.
2645 * Inserts @string at @position in the list of strings stored in @combo_box.
2646 * Note that you can only use this function with combo boxes constructed
2647 * with gtk_combo_box_new_text().
2652 gtk_combo_box_insert_text (GtkComboBox *combo_box,
2657 GtkListStore *store;
2659 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2660 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2661 g_return_if_fail (position >= 0);
2662 g_return_if_fail (text != NULL);
2664 store = GTK_LIST_STORE (combo_box->priv->model);
2666 gtk_list_store_insert (store, &iter, position);
2667 gtk_list_store_set (store, &iter, 0, text, -1);
2671 * gtk_combo_box_prepend_text:
2672 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2675 * Prepends @string to the list of strings stored in @combo_box. Note that
2676 * you can only use this function with combo boxes constructed with
2677 * gtk_combo_box_new_text().
2682 gtk_combo_box_prepend_text (GtkComboBox *combo_box,
2686 GtkListStore *store;
2688 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2689 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2690 g_return_if_fail (text != NULL);
2692 store = GTK_LIST_STORE (combo_box->priv->model);
2694 gtk_list_store_prepend (store, &iter);
2695 gtk_list_store_set (store, &iter, 0, text, -1);
2699 * gtk_combo_box_remove_text:
2700 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2701 * @position: Index of the item to remove.
2703 * Removes the string at @position from @combo_box. Note that you can only use
2704 * this function with combo boxes constructed with gtk_combo_box_new_text().
2709 gtk_combo_box_remove_text (GtkComboBox *combo_box,
2713 GtkListStore *store;
2715 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2716 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2717 g_return_if_fail (position >= 0);
2719 store = GTK_LIST_STORE (combo_box->priv->model);
2721 if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter,
2723 gtk_list_store_remove (store, &iter);