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);
255 static void gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout,
256 GtkCellRenderer *cell,
261 gtk_combo_box_get_type (void)
263 static GType combo_box_type = 0;
267 static const GTypeInfo combo_box_info =
269 sizeof (GtkComboBoxClass),
270 NULL, /* base_init */
271 NULL, /* base_finalize */
272 (GClassInitFunc) gtk_combo_box_class_init,
273 NULL, /* class_finalize */
274 NULL, /* class_data */
275 sizeof (GtkComboBox),
277 (GInstanceInitFunc) gtk_combo_box_init
280 static const GInterfaceInfo cell_layout_info =
282 (GInterfaceInitFunc) gtk_combo_box_cell_layout_init,
287 combo_box_type = g_type_register_static (GTK_TYPE_BIN,
292 g_type_add_interface_static (combo_box_type,
293 GTK_TYPE_CELL_LAYOUT,
297 return combo_box_type;
302 gtk_combo_box_class_init (GtkComboBoxClass *klass)
304 GObjectClass *object_class;
305 GtkBindingSet *binding_set;
306 GtkContainerClass *container_class;
307 GtkWidgetClass *widget_class;
309 binding_set = gtk_binding_set_by_class (klass);
311 container_class = (GtkContainerClass *)klass;
312 container_class->forall = gtk_combo_box_forall;
313 container_class->add = gtk_combo_box_add;
315 widget_class = (GtkWidgetClass *)klass;
316 widget_class->size_allocate = gtk_combo_box_size_allocate;
317 widget_class->size_request = gtk_combo_box_size_request;
318 widget_class->expose_event = gtk_combo_box_expose_event;
319 widget_class->scroll_event = gtk_combo_box_scroll_event;
321 object_class = (GObjectClass *)klass;
322 object_class->set_property = gtk_combo_box_set_property;
323 object_class->get_property = gtk_combo_box_get_property;
325 parent_class = g_type_class_peek_parent (klass);
328 combo_box_signals[CHANGED] =
329 g_signal_new ("changed",
330 G_OBJECT_CLASS_TYPE (klass),
332 G_STRUCT_OFFSET (GtkComboBoxClass, changed),
334 g_cclosure_marshal_VOID__VOID,
338 g_object_class_install_property (object_class,
340 g_param_spec_object ("model",
342 _("The model for the combo box"),
346 g_object_class_install_property (object_class,
348 g_param_spec_int ("wrap_width",
350 _("Wrap width for layouting the items in a grid"),
356 g_object_class_install_property (object_class,
357 PROP_ROW_SPAN_COLUMN,
358 g_param_spec_int ("row_span_column",
359 _("Row span column"),
360 _("TreeModel column containing the row span values"),
366 g_object_class_install_property (object_class,
367 PROP_COLUMN_SPAN_COLUMN,
368 g_param_spec_int ("column_span_column",
369 _("Column span column"),
370 _("TreeModel column containing the column span values"),
376 g_object_class_install_property (object_class,
378 g_param_spec_int ("active",
380 _("The item which is currently active"),
386 gtk_widget_class_install_style_property (widget_class,
387 g_param_spec_boolean ("appearance",
388 _("ComboBox appareance"),
389 _("ComboBox appearance, where TRUE means Windows-style."),
393 g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
397 gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
399 iface->pack_start = gtk_combo_box_cell_layout_pack_start;
400 iface->pack_end = gtk_combo_box_cell_layout_pack_end;
401 iface->clear = gtk_combo_box_cell_layout_clear;
402 iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
403 iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
404 iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
405 iface->reorder = gtk_combo_box_cell_layout_reorder;
409 gtk_combo_box_init (GtkComboBox *combo_box)
411 combo_box->priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
413 g_signal_connect (combo_box, "style_set",
414 G_CALLBACK (gtk_combo_box_style_set), NULL);
416 combo_box->priv->cell_view = gtk_cell_view_new ();
417 gtk_container_add (GTK_CONTAINER (combo_box), combo_box->priv->cell_view);
418 gtk_widget_show (combo_box->priv->cell_view);
420 combo_box->priv->width = 0;
421 combo_box->priv->wrap_width = 0;
423 combo_box->priv->active_item = -1;
424 combo_box->priv->col_column = -1;
425 combo_box->priv->row_column = -1;
429 gtk_combo_box_set_property (GObject *object,
434 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
439 gtk_combo_box_set_model (combo_box, g_value_get_object (value));
442 case PROP_WRAP_WIDTH:
443 gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
446 case PROP_ROW_SPAN_COLUMN:
447 gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
450 case PROP_COLUMN_SPAN_COLUMN:
451 gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
455 gtk_combo_box_set_active (combo_box, g_value_get_int (value));
464 gtk_combo_box_get_property (GObject *object,
469 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
474 g_value_set_object (value, combo_box->priv->model);
477 case PROP_WRAP_WIDTH:
478 g_value_set_int (value, combo_box->priv->wrap_width);
481 case PROP_ROW_SPAN_COLUMN:
482 g_value_set_int (value, combo_box->priv->row_column);
485 case PROP_COLUMN_SPAN_COLUMN:
486 g_value_set_int (value, combo_box->priv->col_column);
490 g_value_set_int (value, gtk_combo_box_get_active (combo_box));
494 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
500 gtk_combo_box_style_set (GtkWidget *widget,
501 GtkStyle *previous_style,
505 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
507 gtk_widget_queue_resize (widget);
509 /* if wrap_width > 0, then we are in grid-mode and forced to use
512 if (combo_box->priv->wrap_width)
515 gtk_widget_style_get (widget,
516 "appearance", &appearance,
519 /* TRUE is windows style */
522 if (GTK_IS_MENU (combo_box->priv->popup_widget))
523 gtk_combo_box_menu_destroy (combo_box);
524 gtk_combo_box_list_setup (combo_box);
528 if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
529 gtk_combo_box_list_destroy (combo_box);
530 gtk_combo_box_menu_setup (combo_box, TRUE);
535 gtk_combo_box_button_toggled (GtkWidget *widget,
538 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
540 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
542 if (!combo_box->priv->popup_in_progress)
543 gtk_combo_box_popup (combo_box);
546 gtk_combo_box_popdown (combo_box);
550 gtk_combo_box_add (GtkContainer *container,
553 GtkComboBox *combo_box = GTK_COMBO_BOX (container);
555 if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent)
557 gtk_container_remove (container, combo_box->priv->cell_view);
558 (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
562 (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
565 if (combo_box->priv->cell_view &&
566 widget != combo_box->priv->cell_view)
568 /* since the cell_view was unparented, it's gone now */
569 combo_box->priv->cell_view = NULL;
571 if (!combo_box->priv->tree_view && combo_box->priv->separator)
573 gtk_widget_unparent (combo_box->priv->separator);
575 g_object_ref (G_OBJECT (combo_box->priv->arrow));
576 gtk_widget_unparent (combo_box->priv->arrow);
577 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
578 combo_box->priv->arrow);
579 g_object_unref (G_OBJECT (combo_box->priv->arrow));
581 gtk_widget_queue_resize (GTK_WIDGET (container));
583 else if (combo_box->priv->cell_view_frame)
585 gtk_widget_unparent (combo_box->priv->cell_view_frame);
586 combo_box->priv->cell_view_frame = NULL;
591 static ComboCellInfo *
592 gtk_combo_box_get_cell_info (GtkComboBox *combo_box,
593 GtkCellRenderer *cell)
597 for (i = combo_box->priv->cells; i; i = i->next)
599 ComboCellInfo *info = (ComboCellInfo *)i->data;
601 if (info->cell == cell)
609 gtk_combo_box_menu_show (GtkWidget *menu,
612 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
614 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
616 combo_box->priv->popup_in_progress = FALSE;
620 gtk_combo_box_menu_hide (GtkWidget *menu,
623 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
625 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
630 gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
633 if (GTK_IS_MENU (combo_box->priv->popup_widget))
634 combo_box->priv->popup_widget = NULL;
635 else if (combo_box->priv->popup_widget)
637 gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame),
638 combo_box->priv->popup_widget);
639 g_object_unref (G_OBJECT (combo_box->priv->popup_widget));
640 combo_box->priv->popup_widget = NULL;
643 if (GTK_IS_MENU (popup))
645 if (combo_box->priv->popup_window)
647 gtk_widget_destroy (combo_box->priv->popup_window);
648 combo_box->priv->popup_window = combo_box->priv->popup_frame = NULL;
651 combo_box->priv->popup_widget = popup;
653 g_signal_connect (popup, "show",
654 G_CALLBACK (gtk_combo_box_menu_show), combo_box);
655 g_signal_connect (popup, "hide",
656 G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
658 /* FIXME: need to attach to widget? */
662 if (!combo_box->priv->popup_window)
664 combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
666 combo_box->priv->popup_frame = gtk_frame_new (NULL);
667 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame),
669 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window),
670 combo_box->priv->popup_frame);
671 gtk_widget_show (combo_box->priv->popup_frame);
674 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame),
676 gtk_widget_show (popup);
677 g_object_ref (G_OBJECT (popup));
678 combo_box->priv->popup_widget = popup;
683 gtk_combo_box_menu_position (GtkMenu *menu,
692 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
694 /* FIXME: is using the size request here broken? */
695 child = GTK_BIN (combo_box)->child;
697 gdk_window_get_origin (child->window, &sx, &sy);
699 gtk_widget_size_request (GTK_WIDGET (menu), &req);
701 if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL)
704 *x = sx + child->allocation.width - req.width;
705 *y = sy + child->allocation.height;
707 if (GTK_WIDGET_NO_WINDOW (child))
709 *x += child->allocation.x;
710 *y += child->allocation.y;
717 gtk_combo_box_popup (GtkComboBox *combo_box)
719 gint x, y, width, height;
722 if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
725 if (GTK_IS_MENU (combo_box->priv->popup_widget))
727 if (combo_box->priv->active_item != -1)
731 childs = gtk_container_get_children (GTK_CONTAINER (combo_box->priv->popup_widget));
732 gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
733 g_list_nth_data (childs, combo_box->priv->active_item));
734 g_list_free (childs);
737 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
739 gtk_combo_box_menu_position, combo_box,
745 sample = GTK_BIN (combo_box)->child;
747 width = sample->allocation.width;
748 height = sample->allocation.height;
750 gdk_window_get_origin (sample->window,
753 if (combo_box->priv->cell_view_frame)
755 x -= GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
756 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
757 width += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
758 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
761 gtk_widget_set_size_request (combo_box->priv->popup_window,
764 if (GTK_WIDGET_NO_WINDOW (sample))
766 x += sample->allocation.x;
767 y += sample->allocation.y;
770 gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window),
774 gtk_widget_show_all (combo_box->priv->popup_window);
776 gtk_widget_grab_focus (combo_box->priv->popup_window);
777 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
780 if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view))
782 gdk_keyboard_grab (combo_box->priv->popup_window->window,
783 FALSE, GDK_CURRENT_TIME);
784 gtk_widget_grab_focus (combo_box->priv->tree_view);
789 gtk_combo_box_popdown (GtkComboBox *combo_box)
791 if (GTK_IS_MENU (combo_box->priv->popup_widget))
793 gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget));
797 gtk_widget_hide_all (combo_box->priv->popup_window);
798 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
803 gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
809 if (combo_box->priv->cell_view)
810 gtk_widget_style_get (combo_box->priv->cell_view,
811 "focus-line-width", &padding,
816 /* add some pixels for good measure */
817 padding += BONUS_PADDING;
819 if (combo_box->priv->cell_view)
820 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
825 return req.width + padding;
829 gtk_combo_box_remeasure (GtkComboBox *combo_box)
835 if (!gtk_tree_model_get_iter_first (combo_box->priv->model, &iter))
838 combo_box->priv->width = 0;
840 path = gtk_tree_path_new_from_indices (0, -1);
842 if (combo_box->priv->cell_view)
843 gtk_widget_style_get (combo_box->priv->cell_view,
844 "focus-line-width", &padding,
849 /* add some pixels for good measure */
850 padding += BONUS_PADDING;
856 if (combo_box->priv->cell_view)
857 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
862 combo_box->priv->width = MAX (combo_box->priv->width,
863 req.width + padding);
865 gtk_tree_path_next (path);
867 while (gtk_tree_model_iter_next (combo_box->priv->model, &iter));
869 gtk_tree_path_free (path);
873 gtk_combo_box_size_request (GtkWidget *widget,
874 GtkRequisition *requisition)
877 GtkRequisition bin_req;
879 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
882 gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
883 gtk_combo_box_remeasure (combo_box);
884 bin_req.width = MAX (bin_req.width, combo_box->priv->width);
886 if (!combo_box->priv->tree_view)
890 if (combo_box->priv->cell_view)
892 GtkRequisition sep_req, arrow_req;
893 gint border_width, xthickness, ythickness;
895 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
896 xthickness = combo_box->priv->button->style->xthickness;
897 ythickness = combo_box->priv->button->style->ythickness;
899 bin_req.width = MAX (bin_req.width, combo_box->priv->width);
901 gtk_widget_size_request (combo_box->priv->separator, &sep_req);
902 gtk_widget_size_request (combo_box->priv->arrow, &arrow_req);
904 height = MAX (sep_req.height, arrow_req.height);
905 height = MAX (height, bin_req.height);
907 width = bin_req.width + sep_req.width + arrow_req.width;
909 height += border_width + 1 + xthickness * 2 + 4;
910 width += border_width + 1 + ythickness * 2 + 4;
912 requisition->width = width;
913 requisition->height = height;
917 GtkRequisition but_req;
919 gtk_widget_size_request (combo_box->priv->button, &but_req);
921 requisition->width = bin_req.width + but_req.width;
922 requisition->height = MAX (bin_req.height, but_req.height);
928 GtkRequisition button_req;
931 *requisition = bin_req;
933 if (combo_box->priv->cell_view_frame)
935 requisition->width += 2 *
936 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
937 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
938 requisition->height += 2 *
939 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
940 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
944 gtk_widget_size_request (combo_box->priv->button, &button_req);
946 requisition->height = MAX (requisition->height, button_req.height);
947 requisition->width += button_req.width;
952 gtk_combo_box_size_allocate (GtkWidget *widget,
953 GtkAllocation *allocation)
955 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
958 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
960 widget->allocation = *allocation;
962 if (!combo_box->priv->tree_view)
964 if (combo_box->priv->cell_view)
966 gint border_width, xthickness, ythickness;
970 gtk_widget_size_allocate (combo_box->priv->button, allocation);
972 /* set some things ready */
973 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
974 xthickness = combo_box->priv->button->style->xthickness;
975 ythickness = combo_box->priv->button->style->ythickness;
977 child.x = allocation->x + border_width + 1 + xthickness + 2;
978 child.y = allocation->y + border_width + 1 + ythickness + 2;
980 width = allocation->width - (border_width + 1 + xthickness * 2 + 4);
982 /* handle the childs */
983 gtk_widget_size_request (combo_box->priv->arrow, &req);
984 child.width = req.width;
985 child.height = allocation->height - 2 * (child.y - allocation->y);
987 child.x += width - req.width;
988 gtk_widget_size_allocate (combo_box->priv->arrow, &child);
990 child.x += req.width;
991 gtk_widget_size_request (combo_box->priv->separator, &req);
992 child.width = req.width;
994 child.x -= req.width;
995 gtk_widget_size_allocate (combo_box->priv->separator, &child);
999 child.x += req.width;
1000 child.width = allocation->x + allocation->width
1001 - (border_width + 1 + xthickness + 2) - child.x;
1005 child.width = child.x;
1006 child.x = allocation->x + border_width + 1 + xthickness + 2;
1007 child.width -= child.x;
1010 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
1014 gtk_widget_size_request (combo_box->priv->button, &req);
1016 child.x = allocation->x;
1018 child.x = allocation->x + allocation->width - req.width;
1019 child.y = allocation->y;
1020 child.width = req.width;
1021 child.height = allocation->height;
1022 gtk_widget_size_allocate (combo_box->priv->button, &child);
1025 child.x = allocation->x + req.width;
1027 child.x = allocation->x;
1028 child.y = allocation->y;
1029 child.width = allocation->width - req.width;
1030 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
1038 gtk_widget_size_request (combo_box->priv->button, &req);
1040 child.x = allocation->x;
1042 child.x += allocation->x + allocation->width - req.width;
1043 child.y = allocation->y;
1044 child.width = req.width;
1045 child.height = allocation->height;
1046 gtk_widget_size_allocate (combo_box->priv->button, &child);
1050 child.x = allocation->x + req.width;
1052 child.x = allocation->x;
1053 child.y = allocation->y;
1054 child.width = allocation->width - req.width;
1055 child.height = allocation->height;
1057 if (combo_box->priv->cell_view_frame)
1059 gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child);
1063 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1064 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
1066 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1067 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
1068 child.width -= 2 * (
1069 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1070 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
1071 child.height -= 2 * (
1072 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1073 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
1076 gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
1081 gtk_combo_box_unset_model (GtkComboBox *combo_box)
1083 if (!combo_box->priv->tree_view)
1086 g_signal_handler_disconnect (combo_box->priv->model,
1087 combo_box->priv->inserted_id);
1088 g_signal_handler_disconnect (combo_box->priv->model,
1089 combo_box->priv->deleted_id);
1090 g_signal_handler_disconnect (combo_box->priv->model,
1091 combo_box->priv->changed_id);
1093 combo_box->priv->inserted_id =
1094 combo_box->priv->deleted_id =
1095 combo_box->priv->changed_id = -1;
1097 if (combo_box->priv->popup_widget)
1098 gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget),
1099 (GtkCallback)gtk_widget_destroy, NULL);
1104 g_signal_handler_disconnect (combo_box->priv->model,
1105 combo_box->priv->changed_id);
1106 combo_box->priv->changed_id = -1;
1111 gtk_combo_box_set_model_internal (GtkComboBox *combo_box)
1113 if (!combo_box->priv->tree_view)
1116 combo_box->priv->inserted_id =
1117 g_signal_connect (combo_box->priv->model, "row_inserted",
1118 G_CALLBACK (gtk_combo_box_menu_row_inserted),
1120 combo_box->priv->deleted_id =
1121 g_signal_connect (combo_box->priv->model, "row_deleted",
1122 G_CALLBACK (gtk_combo_box_menu_row_deleted),
1124 combo_box->priv->changed_id =
1125 g_signal_connect (combo_box->priv->model, "row_changed",
1126 G_CALLBACK (gtk_combo_box_menu_row_changed),
1132 gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
1133 combo_box->priv->model);
1135 combo_box->priv->changed_id =
1136 g_signal_connect (combo_box->priv->model, "row_changed",
1137 G_CALLBACK (gtk_combo_box_list_row_changed),
1143 gtk_combo_box_forall (GtkContainer *container,
1144 gboolean include_internals,
1145 GtkCallback callback,
1146 gpointer callback_data)
1148 GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1150 if (include_internals)
1152 if (!combo_box->priv->tree_view)
1154 if (combo_box->priv->cell_view && combo_box->priv->button)
1156 (* callback) (combo_box->priv->button, callback_data);
1157 (* callback) (combo_box->priv->separator, callback_data);
1158 (* callback) (combo_box->priv->arrow, callback_data);
1160 else if (combo_box->priv->arrow)
1162 (* callback) (combo_box->priv->button, callback_data);
1163 (* callback) (combo_box->priv->arrow, callback_data);
1168 (* callback) (combo_box->priv->button, callback_data);
1169 if (combo_box->priv->cell_view_frame)
1170 (* callback) (combo_box->priv->cell_view_frame, callback_data);
1174 if (GTK_BIN (container)->child)
1175 (* callback) (GTK_BIN (container)->child, callback_data);
1179 gtk_combo_box_expose_event (GtkWidget *widget,
1180 GdkEventExpose *event)
1182 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1184 if (!combo_box->priv->tree_view)
1186 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1187 combo_box->priv->button, event);
1189 if (combo_box->priv->separator)
1191 gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1192 combo_box->priv->separator, event);
1194 /* if not in this case, arrow gets its expose event from button */
1195 gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1196 combo_box->priv->arrow, event);
1201 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1202 combo_box->priv->button, event);
1204 if (combo_box->priv->cell_view_frame)
1205 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1206 combo_box->priv->cell_view_frame, event);
1209 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1210 GTK_BIN (widget)->child, event);
1216 gtk_combo_box_scroll_event (GtkWidget *widget,
1217 GdkEventScroll *event)
1219 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1223 index = gtk_combo_box_get_active (combo_box);
1227 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1229 if (event->direction == GDK_SCROLL_UP)
1234 gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
1245 cell_view_sync_cells (GtkComboBox *combo_box,
1246 GtkCellView *cell_view)
1250 for (k = combo_box->priv->cells; k; k = k->next)
1253 ComboCellInfo *info = (ComboCellInfo *)k->data;
1255 if (info->pack == GTK_PACK_START)
1256 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view),
1257 info->cell, info->expand);
1258 else if (info->pack == GTK_PACK_END)
1259 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view),
1260 info->cell, info->expand);
1262 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view),
1264 info->func, info->func_data, NULL);
1266 for (j = info->attributes; j; j = j->next->next)
1268 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view),
1271 GPOINTER_TO_INT (j->next->data));
1277 gtk_combo_box_menu_setup (GtkComboBox *combo_box,
1278 gboolean add_childs)
1282 if (combo_box->priv->cell_view)
1284 combo_box->priv->button = gtk_toggle_button_new ();
1285 g_signal_connect (combo_box->priv->button, "toggled",
1286 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1287 gtk_widget_set_parent (combo_box->priv->button,
1288 GTK_BIN (combo_box)->child->parent);
1290 combo_box->priv->separator = gtk_vseparator_new ();
1291 gtk_widget_set_parent (combo_box->priv->separator,
1292 combo_box->priv->button);
1293 gtk_widget_show (combo_box->priv->separator);
1295 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1296 gtk_widget_set_parent (combo_box->priv->arrow, combo_box->priv->button);
1297 gtk_widget_show (combo_box->priv->arrow);
1299 gtk_widget_show_all (combo_box->priv->button);
1301 if (GTK_WIDGET_MAPPED (GTK_BIN (combo_box)->child))
1303 /* I have no clue why, but we need to manually map in this case. */
1304 gtk_widget_map (combo_box->priv->separator);
1305 gtk_widget_map (combo_box->priv->arrow);
1310 combo_box->priv->button = gtk_toggle_button_new ();
1311 g_signal_connect (combo_box->priv->button, "toggled",
1312 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1313 gtk_widget_set_parent (combo_box->priv->button,
1314 GTK_BIN (combo_box)->child->parent);
1316 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1317 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1318 combo_box->priv->arrow);
1319 gtk_widget_show_all (combo_box->priv->button);
1322 g_signal_connect (combo_box->priv->button, "button_press_event",
1323 G_CALLBACK (gtk_combo_box_menu_button_press),
1326 /* create our funky menu */
1327 box = gtk_menu_new ();
1328 gtk_combo_box_set_popup_widget (combo_box, box);
1332 gtk_combo_box_menu_fill (combo_box);
1336 gtk_combo_box_menu_fill (GtkComboBox *combo_box)
1342 if (!combo_box->priv->model)
1345 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1346 menu = combo_box->priv->popup_widget;
1348 for (i = 0; i < items; i++)
1352 path = gtk_tree_path_new_from_indices (i, -1);
1353 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1355 g_signal_connect (tmp, "activate",
1356 G_CALLBACK (gtk_combo_box_menu_item_activate),
1359 cell_view_sync_cells (combo_box,
1360 GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1362 gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp);
1363 gtk_widget_show (tmp);
1365 gtk_tree_path_free (path);
1370 gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
1372 /* disconnect signal handlers */
1373 gtk_combo_box_unset_model (combo_box);
1375 g_signal_handlers_disconnect_matched (combo_box->priv->button,
1376 G_SIGNAL_MATCH_DATA,
1378 gtk_combo_box_menu_button_press, NULL);
1380 /* unparent will remove our latest ref */
1381 if (combo_box->priv->cell_view)
1383 gtk_widget_unparent (combo_box->priv->arrow);
1384 gtk_widget_unparent (combo_box->priv->separator);
1385 gtk_widget_unparent (combo_box->priv->button);
1389 /* will destroy the arrow too */
1390 gtk_widget_unparent (combo_box->priv->button);
1393 /* changing the popup window will unref the menu and the childs */
1401 gtk_combo_box_item_get_size (GtkComboBox *combo_box,
1408 gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index);
1412 if (combo_box->priv->col_column == -1)
1415 gtk_tree_model_get (combo_box->priv->model, &iter,
1416 combo_box->priv->col_column, cols,
1422 if (combo_box->priv->row_column == -1)
1425 gtk_tree_model_get (combo_box->priv->model, &iter,
1426 combo_box->priv->row_column, rows,
1432 menu_occupied (GtkMenu *menu,
1436 guint bottom_attach)
1440 g_return_val_if_fail (GTK_IS_MENU (menu), TRUE);
1441 g_return_val_if_fail (left_attach < right_attach, TRUE);
1442 g_return_val_if_fail (top_attach < bottom_attach, TRUE);
1444 for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
1447 gboolean h_intersect = FALSE;
1448 gboolean v_intersect = FALSE;
1450 gtk_container_child_get (GTK_CONTAINER (menu), i->data,
1453 "bottom_attach", &b,
1457 /* look if this item intersects with the given coordinates */
1458 h_intersect = left_attach <= l && l <= right_attach;
1459 h_intersect &= left_attach <= r && r <= right_attach;
1461 v_intersect = top_attach <= t && t <= bottom_attach;
1462 v_intersect &= top_attach <= b && b <= bottom_attach;
1464 if (h_intersect && v_intersect)
1472 gtk_combo_box_relayout_item (GtkComboBox *combo_box,
1475 gint current_col = 0, current_row = 0;
1481 menu = combo_box->priv->popup_widget;
1482 if (!GTK_IS_MENU_SHELL (menu))
1485 list = gtk_container_get_children (GTK_CONTAINER (menu));
1486 item = g_list_nth_data (list, index);
1488 gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
1490 /* look for a good spot */
1493 if (current_col + cols > combo_box->priv->wrap_width)
1499 if (!menu_occupied (GTK_MENU (menu),
1500 current_col, current_col + cols,
1501 current_row, current_row + rows))
1507 /* set attach props */
1508 gtk_menu_attach (GTK_MENU (menu), item,
1509 current_col, current_col + cols,
1510 current_row, current_row + rows);
1514 gtk_combo_box_relayout (GtkComboBox *combo_box)
1520 /* ensure we are in menu style */
1521 if (combo_box->priv->tree_view)
1522 gtk_combo_box_list_destroy (combo_box);
1524 menu = combo_box->priv->popup_widget;
1526 if (!GTK_IS_MENU_SHELL (menu))
1528 gtk_combo_box_menu_setup (combo_box, FALSE);
1529 menu = combo_box->priv->popup_widget;
1532 /* get rid of all children */
1533 g_return_if_fail (GTK_IS_MENU_SHELL (menu));
1535 list = gtk_container_get_children (GTK_CONTAINER (menu));
1537 for (j = g_list_last (list); j; j = j->prev)
1538 gtk_container_remove (GTK_CONTAINER (menu), j->data);
1543 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1545 for (i = 0; i < items; i++)
1550 path = gtk_tree_path_new_from_indices (i, -1);
1551 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1554 g_signal_connect (tmp, "activate",
1555 G_CALLBACK (gtk_combo_box_menu_item_activate),
1558 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1560 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), tmp, i);
1562 if (combo_box->priv->wrap_width)
1563 gtk_combo_box_relayout_item (combo_box, i);
1565 gtk_widget_show (tmp);
1567 gtk_tree_path_free (path);
1573 gtk_combo_box_menu_button_press (GtkWidget *widget,
1574 GdkEventButton *event,
1577 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1579 if (! GTK_IS_MENU (combo_box->priv->popup_widget))
1582 if (event->type == GDK_BUTTON_PRESS && event->button == 1)
1584 combo_box->priv->popup_in_progress = TRUE;
1585 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
1587 gtk_combo_box_menu_position, combo_box,
1588 event->button, event->time);
1597 gtk_combo_box_menu_item_activate (GtkWidget *item,
1602 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1604 menu = combo_box->priv->popup_widget;
1605 g_return_if_fail (GTK_IS_MENU (menu));
1607 index = g_list_index (GTK_MENU_SHELL (menu)->children, item);
1609 gtk_combo_box_set_active (combo_box, index);
1613 gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
1620 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1622 if (!combo_box->priv->popup_widget)
1625 menu = combo_box->priv->popup_widget;
1626 g_return_if_fail (GTK_IS_MENU (menu));
1628 item = gtk_cell_view_menu_item_new_from_model (model, path);
1629 g_signal_connect (item, "activate",
1630 G_CALLBACK (gtk_combo_box_menu_item_activate),
1633 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child));
1635 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item,
1636 gtk_tree_path_get_indices (path)[0]);
1637 gtk_widget_show (item);
1641 gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
1648 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1650 if (!combo_box->priv->popup_widget)
1653 index = gtk_tree_path_get_indices (path)[0];
1654 items = gtk_tree_model_iter_n_children (model, NULL);
1656 if (gtk_combo_box_get_active (combo_box) == index)
1657 gtk_combo_box_set_active (combo_box, index + 1 % items);
1659 menu = combo_box->priv->popup_widget;
1660 g_return_if_fail (GTK_IS_MENU (menu));
1662 item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index);
1663 g_return_if_fail (GTK_IS_MENU_ITEM (item));
1665 gtk_container_remove (GTK_CONTAINER (menu), item);
1669 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
1674 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1677 if (!combo_box->priv->popup_widget)
1680 if (combo_box->priv->wrap_width)
1681 gtk_combo_box_relayout_item (combo_box,
1682 gtk_tree_path_get_indices (path)[0]);
1684 width = gtk_combo_box_calc_requested_width (combo_box, path);
1686 if (width > combo_box->priv->width)
1688 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
1689 gtk_widget_queue_resize (combo_box->priv->cell_view);
1690 combo_box->priv->width = width;
1699 gtk_combo_box_list_setup (GtkComboBox *combo_box)
1702 GtkTreeSelection *sel;
1704 combo_box->priv->button = gtk_toggle_button_new ();
1705 gtk_widget_set_parent (combo_box->priv->button,
1706 GTK_BIN (combo_box)->child->parent);
1707 g_signal_connect (combo_box->priv->button, "button_press_event",
1708 G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
1709 g_signal_connect (combo_box->priv->button, "toggled",
1710 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1712 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1713 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1714 combo_box->priv->arrow);
1715 gtk_widget_show_all (combo_box->priv->button);
1717 if (combo_box->priv->cell_view)
1719 combo_box->priv->cell_view_frame = gtk_frame_new (NULL);
1720 gtk_widget_set_parent (combo_box->priv->cell_view_frame,
1721 GTK_BIN (combo_box)->child->parent);
1722 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
1725 g_object_set (G_OBJECT (combo_box->priv->cell_view),
1726 "background", "white",
1727 "background_set", TRUE,
1730 gtk_widget_show (combo_box->priv->cell_view_frame);
1733 combo_box->priv->tree_view = gtk_tree_view_new ();
1734 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1735 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1736 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view),
1739 g_signal_connect (combo_box->priv->tree_view, "button_press_event",
1740 G_CALLBACK (gtk_combo_box_list_button_pressed),
1742 g_signal_connect (combo_box->priv->tree_view, "button_release_event",
1743 G_CALLBACK (gtk_combo_box_list_button_released),
1745 g_signal_connect (combo_box->priv->tree_view, "key_press_event",
1746 G_CALLBACK (gtk_combo_box_list_key_press),
1749 combo_box->priv->column = gtk_tree_view_column_new ();
1750 gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view),
1751 combo_box->priv->column);
1753 /* set the models */
1754 gtk_combo_box_set_model_internal (combo_box);
1757 for (i = combo_box->priv->cells; i; i = i->next)
1760 ComboCellInfo *info = (ComboCellInfo *)i->data;
1762 if (info->pack == GTK_PACK_START)
1763 gtk_tree_view_column_pack_start (combo_box->priv->column,
1764 info->cell, info->expand);
1765 else if (info->pack == GTK_PACK_END)
1766 gtk_tree_view_column_pack_end (combo_box->priv->column,
1767 info->cell, info->expand);
1769 for (j = info->attributes; j; j = j->next->next)
1771 gtk_tree_view_column_add_attribute (combo_box->priv->column,
1774 GPOINTER_TO_INT (j->next->data));
1778 if (combo_box->priv->active_item != -1)
1782 path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1);
1785 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view),
1787 gtk_tree_path_free (path);
1791 /* set sample/popup widgets */
1792 gtk_combo_box_set_popup_widget (GTK_COMBO_BOX (combo_box),
1793 combo_box->priv->tree_view);
1795 gtk_widget_show (combo_box->priv->tree_view);
1799 gtk_combo_box_list_destroy (GtkComboBox *combo_box)
1801 /* disconnect signals */
1802 gtk_combo_box_unset_model (combo_box);
1804 g_signal_handlers_disconnect_matched (combo_box->priv->tree_view,
1805 G_SIGNAL_MATCH_DATA,
1806 0, 0, NULL, NULL, combo_box);
1807 g_signal_handlers_disconnect_matched (combo_box->priv->button,
1808 G_SIGNAL_MATCH_DATA,
1810 gtk_combo_box_list_button_pressed,
1813 /* destroy things (unparent will kill the latest ref from us)
1814 * last unref on button will destroy the arrow
1816 gtk_widget_unparent (combo_box->priv->button);
1818 if (combo_box->priv->cell_view)
1820 g_object_set (G_OBJECT (combo_box->priv->cell_view),
1821 "background_set", FALSE,
1824 gtk_widget_unparent (combo_box->priv->cell_view_frame);
1827 gtk_widget_destroy (combo_box->priv->tree_view);
1828 combo_box->priv->tree_view = NULL;
1829 combo_box->priv->popup_widget = NULL;
1834 gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box)
1836 if (GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view))
1837 gtk_grab_remove (combo_box->priv->tree_view);
1839 if (GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window))
1841 gtk_grab_remove (combo_box->priv->popup_window);
1842 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1847 gtk_combo_box_list_button_pressed (GtkWidget *widget,
1848 GdkEventButton *event,
1851 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1853 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1855 if (ewidget == combo_box->priv->tree_view)
1858 if ((ewidget != combo_box->priv->button) ||
1859 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1862 gtk_combo_box_popup (combo_box);
1864 gtk_grab_add (combo_box->priv->popup_window);
1865 gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE,
1866 GDK_BUTTON_PRESS_MASK |
1867 GDK_BUTTON_RELEASE_MASK |
1868 GDK_POINTER_MOTION_MASK,
1869 NULL, NULL, GDK_CURRENT_TIME);
1871 gtk_grab_add (combo_box->priv->tree_view);
1873 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
1876 combo_box->priv->popup_in_progress = TRUE;
1882 gtk_combo_box_list_button_released (GtkWidget *widget,
1883 GdkEventButton *event,
1887 GtkTreePath *path = NULL;
1889 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1891 gboolean popup_in_progress = FALSE;
1893 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1895 if (combo_box->priv->popup_in_progress)
1897 popup_in_progress = TRUE;
1898 combo_box->priv->popup_in_progress = FALSE;
1901 if (ewidget != combo_box->priv->tree_view)
1903 if (ewidget == combo_box->priv->button &&
1904 !popup_in_progress &&
1905 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1907 gtk_combo_box_list_remove_grabs (combo_box);
1908 gtk_combo_box_popdown (combo_box);
1912 /* released outside treeview */
1913 if (ewidget != combo_box->priv->button)
1915 gtk_combo_box_list_remove_grabs (combo_box);
1916 gtk_combo_box_popdown (combo_box);
1925 gtk_combo_box_list_remove_grabs (combo_box);
1927 /* select something cool */
1928 ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
1934 return TRUE; /* clicked outside window? */
1936 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1937 gtk_combo_box_popdown (combo_box);
1939 gtk_tree_path_free (path);
1945 gtk_combo_box_list_key_press (GtkWidget *widget,
1949 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1951 if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
1952 event->keyval == GDK_space || event->keyval == GDK_KP_Space) ||
1953 event->keyval == GDK_Escape)
1955 if (event->keyval != GDK_Escape)
1959 GtkTreeModel *model = NULL;
1960 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1962 ret = gtk_tree_selection_get_selected (sel, &model, &iter);
1967 path = gtk_tree_model_get_path (model, &iter);
1970 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1971 gtk_tree_path_free (path);
1976 /* reset active item -- this is incredibly lame and ugly */
1977 gtk_combo_box_set_active (combo_box,
1978 gtk_combo_box_get_active (combo_box));
1980 gtk_combo_box_list_remove_grabs (combo_box);
1981 gtk_combo_box_popdown (combo_box);
1990 gtk_combo_box_list_row_changed (GtkTreeModel *model,
1995 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1998 width = gtk_combo_box_calc_requested_width (combo_box, path);
2000 if (width > combo_box->priv->width)
2002 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
2003 gtk_widget_queue_resize (combo_box->priv->cell_view);
2004 combo_box->priv->width = width;
2009 * GtkCellLayout implementation
2012 gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout,
2013 GtkCellRenderer *cell,
2016 ComboCellInfo *info;
2017 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2020 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2021 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2023 info = g_new0 (ComboCellInfo, 1);
2025 info->expand = expand;
2026 info->pack = GTK_PACK_START;
2028 combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
2030 if (combo_box->priv->cell_view)
2031 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2034 if (combo_box->priv->column)
2035 gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand);
2037 menu = combo_box->priv->popup_widget;
2038 if (GTK_IS_MENU (menu))
2042 list = gtk_container_get_children (GTK_CONTAINER (menu));
2043 for (i = list; i; i = i->next)
2047 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2048 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2050 view = GTK_CELL_VIEW (i->data);
2052 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand);
2059 gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout,
2060 GtkCellRenderer *cell,
2063 ComboCellInfo *info;
2064 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2067 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2068 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2070 info = g_new0 (ComboCellInfo, 1);
2072 info->expand = expand;
2073 info->pack = GTK_PACK_END;
2075 if (combo_box->priv->cell_view)
2076 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2079 if (combo_box->priv->column)
2080 gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand);
2082 menu = combo_box->priv->popup_widget;
2083 if (GTK_IS_MENU (menu))
2087 list = gtk_container_get_children (GTK_CONTAINER (menu));
2088 for (i = list; i; i = i->next)
2092 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2093 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2095 view = GTK_CELL_VIEW (i->data);
2097 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand);
2104 gtk_combo_box_cell_layout_clear (GtkCellLayout *layout)
2107 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2109 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2111 if (combo_box->priv->cell_view)
2112 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view));
2114 if (combo_box->priv->column)
2115 gtk_tree_view_column_clear (combo_box->priv->column);
2117 menu = combo_box->priv->popup_widget;
2118 if (GTK_IS_MENU (menu))
2122 list = gtk_container_get_children (GTK_CONTAINER (menu));
2123 for (i = list; i; i = i->next)
2127 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2128 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2130 view = GTK_CELL_VIEW (i->data);
2132 gtk_cell_layout_clear (GTK_CELL_LAYOUT (view));
2138 gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout,
2139 GtkCellRenderer *cell,
2140 const gchar *attribute,
2143 ComboCellInfo *info;
2144 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2147 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2148 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2150 info = gtk_combo_box_get_cell_info (combo_box, cell);
2152 info->attributes = g_slist_prepend (info->attributes,
2153 GINT_TO_POINTER (column));
2154 info->attributes = g_slist_prepend (info->attributes,
2155 g_strdup (attribute));
2157 if (combo_box->priv->cell_view)
2158 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2159 cell, attribute, column);
2161 if (combo_box->priv->column)
2162 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column),
2163 cell, attribute, column);
2165 menu = combo_box->priv->popup_widget;
2166 if (GTK_IS_MENU (menu))
2170 list = gtk_container_get_children (GTK_CONTAINER (menu));
2171 for (i = list; i; i = i->next)
2175 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2176 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2178 view = GTK_CELL_VIEW (i->data);
2180 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell,
2186 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2190 gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout,
2191 GtkCellRenderer *cell,
2192 GtkCellLayoutDataFunc func,
2194 GDestroyNotify destroy)
2196 ComboCellInfo *info;
2197 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2200 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2202 info = gtk_combo_box_get_cell_info (combo_box, cell);
2203 g_return_if_fail (info != NULL);
2207 GDestroyNotify d = info->destroy;
2209 info->destroy = NULL;
2210 d (info->func_data);
2214 info->func_data = func_data;
2215 info->destroy = destroy;
2217 if (combo_box->priv->cell_view)
2218 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL);
2220 if (combo_box->priv->column)
2221 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL);
2223 menu = combo_box->priv->popup_widget;
2224 if (GTK_IS_MENU (menu))
2228 list = gtk_container_get_children (GTK_CONTAINER (menu));
2229 for (i = list; i; i = i->next)
2233 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2234 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2236 view = GTK_CELL_VIEW (i->data);
2238 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell,
2239 func, func_data, NULL);
2244 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2248 gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout,
2249 GtkCellRenderer *cell)
2251 ComboCellInfo *info;
2252 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2256 g_return_if_fail (GTK_IS_COMBO_BOX (layout));
2257 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2259 info = gtk_combo_box_get_cell_info (combo_box, cell);
2260 g_return_if_fail (info != NULL);
2262 list = info->attributes;
2263 while (list && list->next)
2265 g_free (list->data);
2266 list = list->next->next;
2268 g_slist_free (list);
2270 info->attributes = NULL;
2272 if (combo_box->priv->cell_view)
2273 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell);
2275 if (combo_box->priv->column)
2276 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell);
2278 menu = combo_box->priv->popup_widget;
2279 if (GTK_IS_MENU (menu))
2283 list = gtk_container_get_children (GTK_CONTAINER (menu));
2284 for (i = list; i; i = i->next)
2288 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2289 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2291 view = GTK_CELL_VIEW (i->data);
2293 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell);
2298 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2302 gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout,
2303 GtkCellRenderer *cell,
2306 ComboCellInfo *info;
2307 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2311 g_return_if_fail (GTK_IS_COMBO_BOX (layout));
2312 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2314 info = gtk_combo_box_get_cell_info (combo_box, cell);
2316 g_return_if_fail (info != NULL);
2317 g_return_if_fail (position >= 0);
2319 link = g_slist_find (combo_box->priv->cells, info);
2321 g_return_if_fail (link != NULL);
2323 combo_box->priv->cells = g_slist_remove_link (combo_box->priv->cells, link);
2324 combo_box->priv->cells = g_slist_insert (combo_box->priv->cells, info,
2327 if (combo_box->priv->cell_view)
2328 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2331 if (combo_box->priv->column)
2332 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->column),
2335 menu = combo_box->priv->popup_widget;
2336 if (GTK_IS_MENU (menu))
2340 list = gtk_container_get_children (GTK_CONTAINER (menu));
2341 for (i = list; i; i = i->next)
2345 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2346 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2348 view = GTK_CELL_VIEW (i->data);
2350 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (view), cell, position);
2355 gtk_widget_queue_draw (GTK_WIDGET (combo_box));
2363 * gtk_combo_box_new:
2365 * Creates a new empty #GtkComboBox.
2367 * Return value: A new #GtkComboBox.
2372 gtk_combo_box_new (void)
2374 return GTK_WIDGET (g_object_new (gtk_combo_box_get_type (), NULL));
2378 * gtk_combo_box_new_with_model:
2379 * @model: A #GtkTreeModel.
2381 * Creates a new #GtkComboBox with the model initialized to @model.
2383 * Return value: A new #GtkComboBox.
2388 gtk_combo_box_new_with_model (GtkTreeModel *model)
2390 GtkComboBox *combo_box;
2392 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
2394 combo_box = GTK_COMBO_BOX (g_object_new (gtk_combo_box_get_type (),
2398 return GTK_WIDGET (combo_box);
2402 * gtk_combo_box_set_wrap_width:
2403 * @combo_box: A #GtkComboBox.
2404 * @width: Preferred number of columns.
2406 * Sets the wrap width of @combo_box to be @width. The wrap width is basically
2407 * the preferred number of columns when you want to the popup to be layed out
2413 gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
2416 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2417 g_return_if_fail (width > 0);
2419 combo_box->priv->wrap_width = width;
2421 gtk_combo_box_relayout (combo_box);
2425 * gtk_combo_box_set_row_span_column:
2426 * @combo_box: A #GtkComboBox.
2427 * @row_span: A column in the model passed during construction.
2429 * Sets the column with row span information for @combo_box to be @row_span.
2430 * The row span column contains integers which indicate how many rows
2431 * an item should span.
2436 gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
2441 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2443 col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2444 g_return_if_fail (row_span >= 0 && row_span < col);
2446 combo_box->priv->row_column = row_span;
2448 gtk_combo_box_relayout (combo_box);
2452 * gtk_combo_box_set_column_span_column:
2453 * @combo_box: A #GtkComboBox.
2454 * @column_span: A column in the model passed during construction.
2456 * Sets the column with column span information for @combo_box to be
2457 * @column_span. The column span column contains integers which indicate
2458 * how many columns an item should span.
2463 gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
2468 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2470 col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2471 g_return_if_fail (column_span >= 0 && column_span < col);
2473 combo_box->priv->col_column = column_span;
2475 gtk_combo_box_relayout (combo_box);
2479 * gtk_combo_box_get_active:
2480 * @combo_box: A #GtkComboBox.
2482 * Returns the index of the currently active item, or -1 if there's no
2485 * Return value: An integer which is the index of the currently active item, or
2486 * -1 if there's no active item.
2491 gtk_combo_box_get_active (GtkComboBox *combo_box)
2493 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
2495 return combo_box->priv->active_item;
2499 * gtk_combo_box_set_active:
2500 * @combo_box: A #GtkComboBox.
2501 * @index: An index in the model passed during construction, or -1 to have
2504 * Sets the active item of @combo_box to be the item at @index.
2509 gtk_combo_box_set_active (GtkComboBox *combo_box,
2514 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2515 /* -1 means "no item selected" */
2516 g_return_if_fail (index >= -1);
2518 if (combo_box->priv->active_item == index)
2521 combo_box->priv->active_item = index;
2525 if (combo_box->priv->tree_view)
2526 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)));
2529 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2531 if (GTK_IS_MENU (menu))
2532 gtk_menu_set_active (menu, -1);
2535 if (combo_box->priv->cell_view)
2536 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
2540 path = gtk_tree_path_new_from_indices (index, -1);
2542 if (combo_box->priv->tree_view)
2543 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE);
2546 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2548 if (GTK_IS_MENU (menu))
2549 gtk_menu_set_active (GTK_MENU (menu), index);
2552 if (combo_box->priv->cell_view)
2553 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path);
2555 gtk_tree_path_free (path);
2558 g_signal_emit_by_name (combo_box, "changed", NULL, NULL);
2563 * gtk_combo_box_get_active_iter:
2564 * @combo_box: A #GtkComboBox
2565 * @iter: The uninitialized #GtkTreeIter.
2567 * Set @iter to point to the current active item, if it exists.
2569 * Return value: %TRUE, if @iter was set
2574 gtk_combo_box_get_active_iter (GtkComboBox *combo_box,
2581 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
2583 active = gtk_combo_box_get_active (combo_box);
2587 path = gtk_tree_path_new_from_indices (active, -1);
2588 retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box),
2590 gtk_tree_path_free (path);
2596 * gtk_combo_box_set_active_iter:
2597 * @combo_box: A #GtkComboBox
2598 * @iter: The #GtkTreeIter.
2600 * Sets the current active item to be the one referenced by @iter.
2605 gtk_combo_box_set_active_iter (GtkComboBox *combo_box,
2610 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2612 path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
2613 g_return_if_fail (path != NULL);
2614 g_return_if_fail (gtk_tree_path_get_depth (path) != 1);
2616 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
2617 gtk_tree_path_free (path);
2621 * gtk_combo_box_set_model:
2622 * @combo_box: A #GtkComboBox.
2623 * @model: A #GtkTreeModel.
2625 * Sets the model used by @combo_box to be @model. Will unset a
2626 * previously set model (if applicable).
2631 gtk_combo_box_set_model (GtkComboBox *combo_box,
2632 GtkTreeModel *model)
2634 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2635 g_return_if_fail (GTK_IS_TREE_MODEL (model));
2637 if (combo_box->priv->model)
2639 gtk_combo_box_unset_model (combo_box);
2640 g_object_unref (G_OBJECT (combo_box->priv->model));
2643 combo_box->priv->model = model;
2644 g_object_ref (G_OBJECT (combo_box->priv->model));
2646 gtk_combo_box_set_model_internal (combo_box);
2647 if (!combo_box->priv->tree_view && combo_box->priv->popup_widget)
2648 gtk_combo_box_menu_fill (combo_box);
2650 if (combo_box->priv->cell_view)
2651 gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
2652 combo_box->priv->model);
2656 * gtk_combo_box_get_model
2657 * @combo_box: A #GtkComboBox.
2659 * Returns the #GtkTreeModel which is acting as data source for @combo_box.
2661 * Return value: A #GtkTreeModel which was passed during construction.
2666 gtk_combo_box_get_model (GtkComboBox *combo_box)
2668 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
2670 return combo_box->priv->model;
2674 /* convenience API for simple text combos */
2677 * gtk_combo_box_new_text:
2679 * Convenience function which constructs a new text combo box, which is a
2680 * #GtkComboBox just displaying strings. If you use this function to create
2681 * a text combo box, you only want to manipulate it's data source with the
2682 * following convenience functions: gtk_combo_box_append_text(),
2683 * gtk_combo_box_insert_text() and gtk_combo_box_prepend_text().
2685 * Return value: A new text combo box.
2690 gtk_combo_box_new_text (void)
2692 GtkWidget *combo_box;
2693 GtkCellRenderer *cell;
2694 GtkListStore *store;
2696 store = gtk_list_store_new (1, G_TYPE_STRING);
2698 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
2700 cell = gtk_cell_renderer_text_new ();
2701 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
2702 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
2710 * gtk_combo_box_append_text:
2711 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2714 * Appends @string to the list of strings stored in @combo_box. Note that
2715 * you can only use this function with combo boxes constructed with
2716 * gtk_combo_box_new_text().
2721 gtk_combo_box_append_text (GtkComboBox *combo_box,
2725 GtkListStore *store;
2727 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2728 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2729 g_return_if_fail (text != NULL);
2731 store = GTK_LIST_STORE (combo_box->priv->model);
2733 gtk_list_store_append (store, &iter);
2734 gtk_list_store_set (store, &iter, 0, text, -1);
2738 * gtk_combo_box_insert_text:
2739 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2740 * @position: An index to insert @text.
2743 * Inserts @string at @position in the list of strings stored in @combo_box.
2744 * Note that you can only use this function with combo boxes constructed
2745 * with gtk_combo_box_new_text().
2750 gtk_combo_box_insert_text (GtkComboBox *combo_box,
2755 GtkListStore *store;
2757 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2758 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2759 g_return_if_fail (position >= 0);
2760 g_return_if_fail (text != NULL);
2762 store = GTK_LIST_STORE (combo_box->priv->model);
2764 gtk_list_store_insert (store, &iter, position);
2765 gtk_list_store_set (store, &iter, 0, text, -1);
2769 * gtk_combo_box_prepend_text:
2770 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2773 * Prepends @string to the list of strings stored in @combo_box. Note that
2774 * you can only use this function with combo boxes constructed with
2775 * gtk_combo_box_new_text().
2780 gtk_combo_box_prepend_text (GtkComboBox *combo_box,
2784 GtkListStore *store;
2786 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2787 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2788 g_return_if_fail (text != NULL);
2790 store = GTK_LIST_STORE (combo_box->priv->model);
2792 gtk_list_store_prepend (store, &iter);
2793 gtk_list_store_set (store, &iter, 0, text, -1);
2797 * gtk_combo_box_remove_text:
2798 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2799 * @position: Index of the item to remove.
2801 * Removes the string at @position from @combo_box. Note that you can only use
2802 * this function with combo boxes constructed with gtk_combo_box_new_text().
2807 gtk_combo_box_remove_text (GtkComboBox *combo_box,
2811 GtkListStore *store;
2813 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2814 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2815 g_return_if_fail (position >= 0);
2817 store = GTK_LIST_STORE (combo_box->priv->model);
2819 if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter,
2821 gtk_list_store_remove (store, &iter);