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,
139 static void gtk_combo_box_finalize (GObject *object);
141 static void gtk_combo_box_style_set (GtkWidget *widget,
142 GtkStyle *previous_style,
144 static void gtk_combo_box_button_toggled (GtkWidget *widget,
146 static void gtk_combo_box_add (GtkContainer *container,
149 static ComboCellInfo *gtk_combo_box_get_cell_info (GtkComboBox *combo_box,
150 GtkCellRenderer *cell);
152 static void gtk_combo_box_menu_show (GtkWidget *menu,
154 static void gtk_combo_box_menu_hide (GtkWidget *menu,
157 static void gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
159 static void gtk_combo_box_menu_position (GtkMenu *menu,
164 static void gtk_combo_box_popup (GtkComboBox *combo_box);
165 static void gtk_combo_box_popdown (GtkComboBox *combo_box);
167 static gint gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
169 static void gtk_combo_box_remeasure (GtkComboBox *combo_box);
171 static void gtk_combo_box_unset_model (GtkComboBox *combo_box);
172 static void gtk_combo_box_set_model_internal (GtkComboBox *combo_box);
174 static void gtk_combo_box_size_request (GtkWidget *widget,
175 GtkRequisition *requisition);
176 static void gtk_combo_box_size_allocate (GtkWidget *widget,
177 GtkAllocation *allocation);
178 static void gtk_combo_box_forall (GtkContainer *container,
179 gboolean include_internals,
180 GtkCallback callback,
181 gpointer callback_data);
182 static gboolean gtk_combo_box_expose_event (GtkWidget *widget,
183 GdkEventExpose *event);
184 static gboolean gtk_combo_box_scroll_event (GtkWidget *widget,
185 GdkEventScroll *event);
188 static void gtk_combo_box_list_setup (GtkComboBox *combo_box);
189 static void gtk_combo_box_list_destroy (GtkComboBox *combo_box);
191 static gboolean gtk_combo_box_list_button_released (GtkWidget *widget,
192 GdkEventButton *event,
194 static gboolean gtk_combo_box_list_key_press (GtkWidget *widget,
197 static gboolean gtk_combo_box_list_button_pressed (GtkWidget *widget,
198 GdkEventButton *event,
201 static void gtk_combo_box_list_row_changed (GtkTreeModel *model,
207 static void gtk_combo_box_menu_setup (GtkComboBox *combo_box,
208 gboolean add_childs);
209 static void gtk_combo_box_menu_fill (GtkComboBox *combo_box);
210 static void gtk_combo_box_menu_destroy (GtkComboBox *combo_box);
212 static void gtk_combo_box_item_get_size (GtkComboBox *combo_box,
216 static void gtk_combo_box_relayout_item (GtkComboBox *combo_box,
218 static void gtk_combo_box_relayout (GtkComboBox *combo_box);
220 static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget,
221 GdkEventButton *event,
223 static void gtk_combo_box_menu_item_activate (GtkWidget *item,
225 static void gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
229 static void gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
232 static void gtk_combo_box_menu_row_changed (GtkTreeModel *model,
238 static void gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout,
239 GtkCellRenderer *cell,
241 static void gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout,
242 GtkCellRenderer *cell,
244 static void gtk_combo_box_cell_layout_clear (GtkCellLayout *layout);
245 static void gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout,
246 GtkCellRenderer *cell,
247 const gchar *attribute,
249 static void gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout,
250 GtkCellRenderer *cell,
251 GtkCellLayoutDataFunc func,
253 GDestroyNotify destroy);
254 static void gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout,
255 GtkCellRenderer *cell);
256 static void gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout,
257 GtkCellRenderer *cell,
259 static gboolean gtk_combo_box_mnemonic_activate (GtkWidget *widget,
260 gboolean group_cycling);
264 gtk_combo_box_get_type (void)
266 static GType combo_box_type = 0;
270 static const GTypeInfo combo_box_info =
272 sizeof (GtkComboBoxClass),
273 NULL, /* base_init */
274 NULL, /* base_finalize */
275 (GClassInitFunc) gtk_combo_box_class_init,
276 NULL, /* class_finalize */
277 NULL, /* class_data */
278 sizeof (GtkComboBox),
280 (GInstanceInitFunc) gtk_combo_box_init
283 static const GInterfaceInfo cell_layout_info =
285 (GInterfaceInitFunc) gtk_combo_box_cell_layout_init,
290 combo_box_type = g_type_register_static (GTK_TYPE_BIN,
295 g_type_add_interface_static (combo_box_type,
296 GTK_TYPE_CELL_LAYOUT,
300 return combo_box_type;
305 gtk_combo_box_class_init (GtkComboBoxClass *klass)
307 GObjectClass *object_class;
308 GtkBindingSet *binding_set;
309 GtkContainerClass *container_class;
310 GtkWidgetClass *widget_class;
312 binding_set = gtk_binding_set_by_class (klass);
314 container_class = (GtkContainerClass *)klass;
315 container_class->forall = gtk_combo_box_forall;
316 container_class->add = gtk_combo_box_add;
318 widget_class = (GtkWidgetClass *)klass;
319 widget_class->size_allocate = gtk_combo_box_size_allocate;
320 widget_class->size_request = gtk_combo_box_size_request;
321 widget_class->expose_event = gtk_combo_box_expose_event;
322 widget_class->scroll_event = gtk_combo_box_scroll_event;
323 widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
325 object_class = (GObjectClass *)klass;
326 object_class->finalize = gtk_combo_box_finalize;
327 object_class->set_property = gtk_combo_box_set_property;
328 object_class->get_property = gtk_combo_box_get_property;
330 parent_class = g_type_class_peek_parent (klass);
333 combo_box_signals[CHANGED] =
334 g_signal_new ("changed",
335 G_OBJECT_CLASS_TYPE (klass),
337 G_STRUCT_OFFSET (GtkComboBoxClass, changed),
339 g_cclosure_marshal_VOID__VOID,
343 g_object_class_install_property (object_class,
345 g_param_spec_object ("model",
346 P_("ComboBox model"),
347 P_("The model for the combo box"),
351 g_object_class_install_property (object_class,
353 g_param_spec_int ("wrap_width",
355 P_("Wrap width for layouting the items in a grid"),
361 g_object_class_install_property (object_class,
362 PROP_ROW_SPAN_COLUMN,
363 g_param_spec_int ("row_span_column",
364 P_("Row span column"),
365 P_("TreeModel column containing the row span values"),
371 g_object_class_install_property (object_class,
372 PROP_COLUMN_SPAN_COLUMN,
373 g_param_spec_int ("column_span_column",
374 P_("Column span column"),
375 P_("TreeModel column containing the column span values"),
381 g_object_class_install_property (object_class,
383 g_param_spec_int ("active",
385 P_("The item which is currently active"),
391 gtk_widget_class_install_style_property (widget_class,
392 g_param_spec_boolean ("appearance",
393 P_("ComboBox appareance"),
394 P_("ComboBox appearance, where TRUE means Windows-style."),
398 g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
402 gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
404 iface->pack_start = gtk_combo_box_cell_layout_pack_start;
405 iface->pack_end = gtk_combo_box_cell_layout_pack_end;
406 iface->clear = gtk_combo_box_cell_layout_clear;
407 iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
408 iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
409 iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
410 iface->reorder = gtk_combo_box_cell_layout_reorder;
414 gtk_combo_box_init (GtkComboBox *combo_box)
416 combo_box->priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
418 g_signal_connect (combo_box, "style_set",
419 G_CALLBACK (gtk_combo_box_style_set), NULL);
421 combo_box->priv->cell_view = gtk_cell_view_new ();
422 gtk_container_add (GTK_CONTAINER (combo_box), combo_box->priv->cell_view);
423 gtk_widget_show (combo_box->priv->cell_view);
425 combo_box->priv->width = 0;
426 combo_box->priv->wrap_width = 0;
428 combo_box->priv->active_item = -1;
429 combo_box->priv->col_column = -1;
430 combo_box->priv->row_column = -1;
434 gtk_combo_box_set_property (GObject *object,
439 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
444 gtk_combo_box_set_model (combo_box, g_value_get_object (value));
447 case PROP_WRAP_WIDTH:
448 gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
451 case PROP_ROW_SPAN_COLUMN:
452 gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
455 case PROP_COLUMN_SPAN_COLUMN:
456 gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
460 gtk_combo_box_set_active (combo_box, g_value_get_int (value));
469 gtk_combo_box_get_property (GObject *object,
474 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
479 g_value_set_object (value, combo_box->priv->model);
482 case PROP_WRAP_WIDTH:
483 g_value_set_int (value, combo_box->priv->wrap_width);
486 case PROP_ROW_SPAN_COLUMN:
487 g_value_set_int (value, combo_box->priv->row_column);
490 case PROP_COLUMN_SPAN_COLUMN:
491 g_value_set_int (value, combo_box->priv->col_column);
495 g_value_set_int (value, gtk_combo_box_get_active (combo_box));
499 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
505 gtk_combo_box_style_set (GtkWidget *widget,
506 GtkStyle *previous_style,
510 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
512 gtk_widget_queue_resize (widget);
514 /* if wrap_width > 0, then we are in grid-mode and forced to use
517 if (combo_box->priv->wrap_width)
520 gtk_widget_style_get (widget,
521 "appearance", &appearance,
524 /* TRUE is windows style */
527 if (GTK_IS_MENU (combo_box->priv->popup_widget))
528 gtk_combo_box_menu_destroy (combo_box);
529 gtk_combo_box_list_setup (combo_box);
533 if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
534 gtk_combo_box_list_destroy (combo_box);
535 gtk_combo_box_menu_setup (combo_box, TRUE);
540 gtk_combo_box_button_toggled (GtkWidget *widget,
543 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
545 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
547 if (!combo_box->priv->popup_in_progress)
548 gtk_combo_box_popup (combo_box);
551 gtk_combo_box_popdown (combo_box);
555 gtk_combo_box_add (GtkContainer *container,
558 GtkComboBox *combo_box = GTK_COMBO_BOX (container);
560 if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent)
562 gtk_container_remove (container, combo_box->priv->cell_view);
563 (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
567 (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
570 if (combo_box->priv->cell_view &&
571 widget != combo_box->priv->cell_view)
573 /* since the cell_view was unparented, it's gone now */
574 combo_box->priv->cell_view = NULL;
576 if (!combo_box->priv->tree_view && combo_box->priv->separator)
578 gtk_widget_unparent (combo_box->priv->separator);
580 g_object_ref (G_OBJECT (combo_box->priv->arrow));
581 gtk_widget_unparent (combo_box->priv->arrow);
582 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
583 combo_box->priv->arrow);
584 g_object_unref (G_OBJECT (combo_box->priv->arrow));
586 gtk_widget_queue_resize (GTK_WIDGET (container));
588 else if (combo_box->priv->cell_view_frame)
590 gtk_widget_unparent (combo_box->priv->cell_view_frame);
591 combo_box->priv->cell_view_frame = NULL;
596 static ComboCellInfo *
597 gtk_combo_box_get_cell_info (GtkComboBox *combo_box,
598 GtkCellRenderer *cell)
602 for (i = combo_box->priv->cells; i; i = i->next)
604 ComboCellInfo *info = (ComboCellInfo *)i->data;
606 if (info->cell == cell)
614 gtk_combo_box_menu_show (GtkWidget *menu,
617 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
619 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
621 combo_box->priv->popup_in_progress = FALSE;
625 gtk_combo_box_menu_hide (GtkWidget *menu,
628 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
630 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
635 gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
638 if (GTK_IS_MENU (combo_box->priv->popup_widget))
639 combo_box->priv->popup_widget = NULL;
640 else if (combo_box->priv->popup_widget)
642 gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame),
643 combo_box->priv->popup_widget);
644 g_object_unref (G_OBJECT (combo_box->priv->popup_widget));
645 combo_box->priv->popup_widget = NULL;
648 if (GTK_IS_MENU (popup))
650 if (combo_box->priv->popup_window)
652 gtk_widget_destroy (combo_box->priv->popup_window);
653 combo_box->priv->popup_window = combo_box->priv->popup_frame = NULL;
656 combo_box->priv->popup_widget = popup;
658 g_signal_connect (popup, "show",
659 G_CALLBACK (gtk_combo_box_menu_show), combo_box);
660 g_signal_connect (popup, "hide",
661 G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
663 /* FIXME: need to attach to widget? */
667 if (!combo_box->priv->popup_window)
669 combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
671 combo_box->priv->popup_frame = gtk_frame_new (NULL);
672 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame),
674 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window),
675 combo_box->priv->popup_frame);
676 gtk_widget_show (combo_box->priv->popup_frame);
679 gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame),
681 gtk_widget_show (popup);
682 g_object_ref (G_OBJECT (popup));
683 combo_box->priv->popup_widget = popup;
688 gtk_combo_box_menu_position (GtkMenu *menu,
697 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
699 /* FIXME: is using the size request here broken? */
700 child = GTK_BIN (combo_box)->child;
702 gdk_window_get_origin (child->window, &sx, &sy);
704 gtk_widget_size_request (GTK_WIDGET (menu), &req);
706 if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL)
709 *x = sx + child->allocation.width - req.width;
710 *y = sy + child->allocation.height;
712 if (GTK_WIDGET_NO_WINDOW (child))
714 *x += child->allocation.x;
715 *y += child->allocation.y;
722 gtk_combo_box_popup (GtkComboBox *combo_box)
724 gint x, y, width, height;
727 if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
730 if (GTK_IS_MENU (combo_box->priv->popup_widget))
732 if (combo_box->priv->active_item != -1)
736 childs = gtk_container_get_children (GTK_CONTAINER (combo_box->priv->popup_widget));
737 gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
738 g_list_nth_data (childs, combo_box->priv->active_item));
739 g_list_free (childs);
742 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
744 gtk_combo_box_menu_position, combo_box,
750 sample = GTK_BIN (combo_box)->child;
752 width = sample->allocation.width;
753 height = sample->allocation.height;
755 gdk_window_get_origin (sample->window,
758 if (combo_box->priv->cell_view_frame)
760 x -= GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
761 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
762 width += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
763 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
766 gtk_widget_set_size_request (combo_box->priv->popup_window,
769 if (GTK_WIDGET_NO_WINDOW (sample))
771 x += sample->allocation.x;
772 y += sample->allocation.y;
775 gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window),
779 gtk_widget_show_all (combo_box->priv->popup_window);
781 gtk_widget_grab_focus (combo_box->priv->popup_window);
782 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
785 if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view))
787 gdk_keyboard_grab (combo_box->priv->popup_window->window,
788 FALSE, GDK_CURRENT_TIME);
789 gtk_widget_grab_focus (combo_box->priv->tree_view);
794 gtk_combo_box_popdown (GtkComboBox *combo_box)
796 if (GTK_IS_MENU (combo_box->priv->popup_widget))
798 gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget));
802 gtk_widget_hide_all (combo_box->priv->popup_window);
803 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
808 gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
814 if (combo_box->priv->cell_view)
815 gtk_widget_style_get (combo_box->priv->cell_view,
816 "focus-line-width", &padding,
821 /* add some pixels for good measure */
822 padding += BONUS_PADDING;
824 if (combo_box->priv->cell_view)
825 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
830 return req.width + padding;
834 gtk_combo_box_remeasure (GtkComboBox *combo_box)
840 if (!gtk_tree_model_get_iter_first (combo_box->priv->model, &iter))
843 combo_box->priv->width = 0;
845 path = gtk_tree_path_new_from_indices (0, -1);
847 if (combo_box->priv->cell_view)
848 gtk_widget_style_get (combo_box->priv->cell_view,
849 "focus-line-width", &padding,
854 /* add some pixels for good measure */
855 padding += BONUS_PADDING;
861 if (combo_box->priv->cell_view)
862 gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
867 combo_box->priv->width = MAX (combo_box->priv->width,
868 req.width + padding);
870 gtk_tree_path_next (path);
872 while (gtk_tree_model_iter_next (combo_box->priv->model, &iter));
874 gtk_tree_path_free (path);
878 gtk_combo_box_size_request (GtkWidget *widget,
879 GtkRequisition *requisition)
882 GtkRequisition bin_req;
884 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
887 gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
888 gtk_combo_box_remeasure (combo_box);
889 bin_req.width = MAX (bin_req.width, combo_box->priv->width);
891 if (!combo_box->priv->tree_view)
895 if (combo_box->priv->cell_view)
897 GtkRequisition sep_req, arrow_req;
898 gint border_width, xthickness, ythickness;
900 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
901 xthickness = combo_box->priv->button->style->xthickness;
902 ythickness = combo_box->priv->button->style->ythickness;
904 bin_req.width = MAX (bin_req.width, combo_box->priv->width);
906 gtk_widget_size_request (combo_box->priv->separator, &sep_req);
907 gtk_widget_size_request (combo_box->priv->arrow, &arrow_req);
909 height = MAX (sep_req.height, arrow_req.height);
910 height = MAX (height, bin_req.height);
912 width = bin_req.width + sep_req.width + arrow_req.width;
914 height += border_width + 1 + xthickness * 2 + 4;
915 width += border_width + 1 + ythickness * 2 + 4;
917 requisition->width = width;
918 requisition->height = height;
922 GtkRequisition but_req;
924 gtk_widget_size_request (combo_box->priv->button, &but_req);
926 requisition->width = bin_req.width + but_req.width;
927 requisition->height = MAX (bin_req.height, but_req.height);
933 GtkRequisition button_req;
936 *requisition = bin_req;
938 if (combo_box->priv->cell_view_frame)
940 requisition->width += 2 *
941 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
942 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
943 requisition->height += 2 *
944 (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
945 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
949 gtk_widget_size_request (combo_box->priv->button, &button_req);
951 requisition->height = MAX (requisition->height, button_req.height);
952 requisition->width += button_req.width;
957 gtk_combo_box_size_allocate (GtkWidget *widget,
958 GtkAllocation *allocation)
960 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
963 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
965 widget->allocation = *allocation;
967 if (!combo_box->priv->tree_view)
969 if (combo_box->priv->cell_view)
971 gint border_width, xthickness, ythickness;
975 gtk_widget_size_allocate (combo_box->priv->button, allocation);
977 /* set some things ready */
978 border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
979 xthickness = combo_box->priv->button->style->xthickness;
980 ythickness = combo_box->priv->button->style->ythickness;
982 child.x = allocation->x + border_width + 1 + xthickness + 2;
983 child.y = allocation->y + border_width + 1 + ythickness + 2;
985 width = allocation->width - (border_width + 1 + xthickness * 2 + 4);
987 /* handle the childs */
988 gtk_widget_size_request (combo_box->priv->arrow, &req);
989 child.width = req.width;
990 child.height = allocation->height - 2 * (child.y - allocation->y);
992 child.x += width - req.width;
993 gtk_widget_size_allocate (combo_box->priv->arrow, &child);
995 child.x += req.width;
996 gtk_widget_size_request (combo_box->priv->separator, &req);
997 child.width = req.width;
999 child.x -= req.width;
1000 gtk_widget_size_allocate (combo_box->priv->separator, &child);
1004 child.x += req.width;
1005 child.width = allocation->x + allocation->width
1006 - (border_width + 1 + xthickness + 2) - child.x;
1010 child.width = child.x;
1011 child.x = allocation->x + border_width + 1 + xthickness + 2;
1012 child.width -= child.x;
1015 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
1019 gtk_widget_size_request (combo_box->priv->button, &req);
1021 child.x = allocation->x;
1023 child.x = allocation->x + allocation->width - req.width;
1024 child.y = allocation->y;
1025 child.width = req.width;
1026 child.height = allocation->height;
1027 gtk_widget_size_allocate (combo_box->priv->button, &child);
1030 child.x = allocation->x + req.width;
1032 child.x = allocation->x;
1033 child.y = allocation->y;
1034 child.width = allocation->width - req.width;
1035 gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
1043 gtk_widget_size_request (combo_box->priv->button, &req);
1045 child.x = allocation->x;
1047 child.x += allocation->x + allocation->width - req.width;
1048 child.y = allocation->y;
1049 child.width = req.width;
1050 child.height = allocation->height;
1051 gtk_widget_size_allocate (combo_box->priv->button, &child);
1055 child.x = allocation->x + req.width;
1057 child.x = allocation->x;
1058 child.y = allocation->y;
1059 child.width = allocation->width - req.width;
1060 child.height = allocation->height;
1062 if (combo_box->priv->cell_view_frame)
1064 gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child);
1068 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1069 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
1071 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1072 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
1073 child.width -= 2 * (
1074 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1075 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
1076 child.height -= 2 * (
1077 GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1078 GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
1081 gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
1086 gtk_combo_box_unset_model (GtkComboBox *combo_box)
1088 if (!combo_box->priv->tree_view)
1091 g_signal_handler_disconnect (combo_box->priv->model,
1092 combo_box->priv->inserted_id);
1093 g_signal_handler_disconnect (combo_box->priv->model,
1094 combo_box->priv->deleted_id);
1095 g_signal_handler_disconnect (combo_box->priv->model,
1096 combo_box->priv->changed_id);
1098 combo_box->priv->inserted_id =
1099 combo_box->priv->deleted_id =
1100 combo_box->priv->changed_id = -1;
1102 if (combo_box->priv->popup_widget)
1103 gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget),
1104 (GtkCallback)gtk_widget_destroy, NULL);
1109 g_signal_handler_disconnect (combo_box->priv->model,
1110 combo_box->priv->changed_id);
1111 combo_box->priv->changed_id = -1;
1116 gtk_combo_box_set_model_internal (GtkComboBox *combo_box)
1118 if (!combo_box->priv->tree_view)
1121 combo_box->priv->inserted_id =
1122 g_signal_connect (combo_box->priv->model, "row_inserted",
1123 G_CALLBACK (gtk_combo_box_menu_row_inserted),
1125 combo_box->priv->deleted_id =
1126 g_signal_connect (combo_box->priv->model, "row_deleted",
1127 G_CALLBACK (gtk_combo_box_menu_row_deleted),
1129 combo_box->priv->changed_id =
1130 g_signal_connect (combo_box->priv->model, "row_changed",
1131 G_CALLBACK (gtk_combo_box_menu_row_changed),
1137 gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
1138 combo_box->priv->model);
1140 combo_box->priv->changed_id =
1141 g_signal_connect (combo_box->priv->model, "row_changed",
1142 G_CALLBACK (gtk_combo_box_list_row_changed),
1148 gtk_combo_box_forall (GtkContainer *container,
1149 gboolean include_internals,
1150 GtkCallback callback,
1151 gpointer callback_data)
1153 GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1155 if (include_internals)
1157 if (!combo_box->priv->tree_view)
1159 if (combo_box->priv->cell_view && combo_box->priv->button)
1161 (* callback) (combo_box->priv->button, callback_data);
1162 (* callback) (combo_box->priv->separator, callback_data);
1163 (* callback) (combo_box->priv->arrow, callback_data);
1165 else if (combo_box->priv->arrow)
1167 (* callback) (combo_box->priv->button, callback_data);
1168 (* callback) (combo_box->priv->arrow, callback_data);
1173 (* callback) (combo_box->priv->button, callback_data);
1174 if (combo_box->priv->cell_view_frame)
1175 (* callback) (combo_box->priv->cell_view_frame, callback_data);
1179 if (GTK_BIN (container)->child)
1180 (* callback) (GTK_BIN (container)->child, callback_data);
1184 gtk_combo_box_expose_event (GtkWidget *widget,
1185 GdkEventExpose *event)
1187 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1189 if (!combo_box->priv->tree_view)
1191 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1192 combo_box->priv->button, event);
1194 if (combo_box->priv->separator)
1196 gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1197 combo_box->priv->separator, event);
1199 /* if not in this case, arrow gets its expose event from button */
1200 gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1201 combo_box->priv->arrow, event);
1206 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1207 combo_box->priv->button, event);
1209 if (combo_box->priv->cell_view_frame)
1210 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1211 combo_box->priv->cell_view_frame, event);
1214 gtk_container_propagate_expose (GTK_CONTAINER (widget),
1215 GTK_BIN (widget)->child, event);
1221 gtk_combo_box_scroll_event (GtkWidget *widget,
1222 GdkEventScroll *event)
1224 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1228 index = gtk_combo_box_get_active (combo_box);
1232 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1234 if (event->direction == GDK_SCROLL_UP)
1239 gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
1250 cell_view_sync_cells (GtkComboBox *combo_box,
1251 GtkCellView *cell_view)
1255 for (k = combo_box->priv->cells; k; k = k->next)
1258 ComboCellInfo *info = (ComboCellInfo *)k->data;
1260 if (info->pack == GTK_PACK_START)
1261 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view),
1262 info->cell, info->expand);
1263 else if (info->pack == GTK_PACK_END)
1264 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view),
1265 info->cell, info->expand);
1267 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view),
1269 info->func, info->func_data, NULL);
1271 for (j = info->attributes; j; j = j->next->next)
1273 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view),
1276 GPOINTER_TO_INT (j->next->data));
1282 gtk_combo_box_menu_setup (GtkComboBox *combo_box,
1283 gboolean add_childs)
1287 if (combo_box->priv->cell_view)
1289 combo_box->priv->button = gtk_toggle_button_new ();
1290 g_signal_connect (combo_box->priv->button, "toggled",
1291 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1292 gtk_widget_set_parent (combo_box->priv->button,
1293 GTK_BIN (combo_box)->child->parent);
1295 combo_box->priv->separator = gtk_vseparator_new ();
1296 gtk_widget_set_parent (combo_box->priv->separator,
1297 combo_box->priv->button);
1298 gtk_widget_show (combo_box->priv->separator);
1300 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1301 gtk_widget_set_parent (combo_box->priv->arrow, combo_box->priv->button);
1302 gtk_widget_show (combo_box->priv->arrow);
1304 gtk_widget_show_all (combo_box->priv->button);
1306 if (GTK_WIDGET_MAPPED (GTK_BIN (combo_box)->child))
1308 /* I have no clue why, but we need to manually map in this case. */
1309 gtk_widget_map (combo_box->priv->separator);
1310 gtk_widget_map (combo_box->priv->arrow);
1315 combo_box->priv->button = gtk_toggle_button_new ();
1316 g_signal_connect (combo_box->priv->button, "toggled",
1317 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1318 gtk_widget_set_parent (combo_box->priv->button,
1319 GTK_BIN (combo_box)->child->parent);
1321 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1322 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1323 combo_box->priv->arrow);
1324 gtk_widget_show_all (combo_box->priv->button);
1327 g_signal_connect (combo_box->priv->button, "button_press_event",
1328 G_CALLBACK (gtk_combo_box_menu_button_press),
1331 /* create our funky menu */
1332 box = gtk_menu_new ();
1333 gtk_combo_box_set_popup_widget (combo_box, box);
1337 gtk_combo_box_menu_fill (combo_box);
1341 gtk_combo_box_menu_fill (GtkComboBox *combo_box)
1347 if (!combo_box->priv->model)
1350 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1351 menu = combo_box->priv->popup_widget;
1353 for (i = 0; i < items; i++)
1357 path = gtk_tree_path_new_from_indices (i, -1);
1358 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1360 g_signal_connect (tmp, "activate",
1361 G_CALLBACK (gtk_combo_box_menu_item_activate),
1364 cell_view_sync_cells (combo_box,
1365 GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1367 gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp);
1368 gtk_widget_show (tmp);
1370 gtk_tree_path_free (path);
1375 gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
1377 /* disconnect signal handlers */
1378 gtk_combo_box_unset_model (combo_box);
1380 g_signal_handlers_disconnect_matched (combo_box->priv->button,
1381 G_SIGNAL_MATCH_DATA,
1383 gtk_combo_box_menu_button_press, NULL);
1385 /* unparent will remove our latest ref */
1386 if (combo_box->priv->cell_view)
1388 gtk_widget_unparent (combo_box->priv->arrow);
1389 gtk_widget_unparent (combo_box->priv->separator);
1390 gtk_widget_unparent (combo_box->priv->button);
1394 /* will destroy the arrow too */
1395 gtk_widget_unparent (combo_box->priv->button);
1398 /* changing the popup window will unref the menu and the childs */
1406 gtk_combo_box_item_get_size (GtkComboBox *combo_box,
1413 gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index);
1417 if (combo_box->priv->col_column == -1)
1420 gtk_tree_model_get (combo_box->priv->model, &iter,
1421 combo_box->priv->col_column, cols,
1427 if (combo_box->priv->row_column == -1)
1430 gtk_tree_model_get (combo_box->priv->model, &iter,
1431 combo_box->priv->row_column, rows,
1437 menu_occupied (GtkMenu *menu,
1441 guint bottom_attach)
1445 g_return_val_if_fail (GTK_IS_MENU (menu), TRUE);
1446 g_return_val_if_fail (left_attach < right_attach, TRUE);
1447 g_return_val_if_fail (top_attach < bottom_attach, TRUE);
1449 for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
1452 gboolean h_intersect = FALSE;
1453 gboolean v_intersect = FALSE;
1455 gtk_container_child_get (GTK_CONTAINER (menu), i->data,
1458 "bottom_attach", &b,
1462 /* look if this item intersects with the given coordinates */
1463 h_intersect = left_attach <= l && l <= right_attach;
1464 h_intersect &= left_attach <= r && r <= right_attach;
1466 v_intersect = top_attach <= t && t <= bottom_attach;
1467 v_intersect &= top_attach <= b && b <= bottom_attach;
1469 if (h_intersect && v_intersect)
1477 gtk_combo_box_relayout_item (GtkComboBox *combo_box,
1480 gint current_col = 0, current_row = 0;
1486 menu = combo_box->priv->popup_widget;
1487 if (!GTK_IS_MENU_SHELL (menu))
1490 list = gtk_container_get_children (GTK_CONTAINER (menu));
1491 item = g_list_nth_data (list, index);
1494 gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
1496 /* look for a good spot */
1499 if (current_col + cols > combo_box->priv->wrap_width)
1505 if (!menu_occupied (GTK_MENU (menu),
1506 current_col, current_col + cols,
1507 current_row, current_row + rows))
1513 /* set attach props */
1514 gtk_menu_attach (GTK_MENU (menu), item,
1515 current_col, current_col + cols,
1516 current_row, current_row + rows);
1520 gtk_combo_box_relayout (GtkComboBox *combo_box)
1526 /* ensure we are in menu style */
1527 if (combo_box->priv->tree_view)
1528 gtk_combo_box_list_destroy (combo_box);
1530 menu = combo_box->priv->popup_widget;
1532 if (!GTK_IS_MENU_SHELL (menu))
1534 gtk_combo_box_menu_setup (combo_box, FALSE);
1535 menu = combo_box->priv->popup_widget;
1538 /* get rid of all children */
1539 g_return_if_fail (GTK_IS_MENU_SHELL (menu));
1541 list = gtk_container_get_children (GTK_CONTAINER (menu));
1543 for (j = g_list_last (list); j; j = j->prev)
1544 gtk_container_remove (GTK_CONTAINER (menu), j->data);
1549 items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1551 for (i = 0; i < items; i++)
1556 path = gtk_tree_path_new_from_indices (i, -1);
1557 tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1560 g_signal_connect (tmp, "activate",
1561 G_CALLBACK (gtk_combo_box_menu_item_activate),
1564 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1566 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), tmp, i);
1568 if (combo_box->priv->wrap_width)
1569 gtk_combo_box_relayout_item (combo_box, i);
1571 gtk_widget_show (tmp);
1573 gtk_tree_path_free (path);
1579 gtk_combo_box_menu_button_press (GtkWidget *widget,
1580 GdkEventButton *event,
1583 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1585 if (! GTK_IS_MENU (combo_box->priv->popup_widget))
1588 if (event->type == GDK_BUTTON_PRESS && event->button == 1)
1590 combo_box->priv->popup_in_progress = TRUE;
1591 gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
1593 gtk_combo_box_menu_position, combo_box,
1594 event->button, event->time);
1603 gtk_combo_box_menu_item_activate (GtkWidget *item,
1608 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1610 menu = combo_box->priv->popup_widget;
1611 g_return_if_fail (GTK_IS_MENU (menu));
1613 index = g_list_index (GTK_MENU_SHELL (menu)->children, item);
1615 gtk_combo_box_set_active (combo_box, index);
1619 gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
1626 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1628 if (!combo_box->priv->popup_widget)
1631 menu = combo_box->priv->popup_widget;
1632 g_return_if_fail (GTK_IS_MENU (menu));
1634 item = gtk_cell_view_menu_item_new_from_model (model, path);
1635 g_signal_connect (item, "activate",
1636 G_CALLBACK (gtk_combo_box_menu_item_activate),
1639 cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child));
1641 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item,
1642 gtk_tree_path_get_indices (path)[0]);
1643 gtk_widget_show (item);
1647 gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
1654 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1656 if (!combo_box->priv->popup_widget)
1659 index = gtk_tree_path_get_indices (path)[0];
1660 items = gtk_tree_model_iter_n_children (model, NULL);
1662 if (gtk_combo_box_get_active (combo_box) == index)
1663 gtk_combo_box_set_active (combo_box, index + 1 % items);
1665 menu = combo_box->priv->popup_widget;
1666 g_return_if_fail (GTK_IS_MENU (menu));
1668 item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index);
1669 g_return_if_fail (GTK_IS_MENU_ITEM (item));
1671 gtk_container_remove (GTK_CONTAINER (menu), item);
1675 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
1680 GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1683 if (!combo_box->priv->popup_widget)
1686 if (combo_box->priv->wrap_width)
1687 gtk_combo_box_relayout_item (combo_box,
1688 gtk_tree_path_get_indices (path)[0]);
1690 width = gtk_combo_box_calc_requested_width (combo_box, path);
1692 if (width > combo_box->priv->width)
1694 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
1695 gtk_widget_queue_resize (combo_box->priv->cell_view);
1696 combo_box->priv->width = width;
1705 gtk_combo_box_list_setup (GtkComboBox *combo_box)
1708 GtkTreeSelection *sel;
1710 combo_box->priv->button = gtk_toggle_button_new ();
1711 gtk_widget_set_parent (combo_box->priv->button,
1712 GTK_BIN (combo_box)->child->parent);
1713 g_signal_connect (combo_box->priv->button, "button_press_event",
1714 G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
1715 g_signal_connect (combo_box->priv->button, "toggled",
1716 G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1718 combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1719 gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1720 combo_box->priv->arrow);
1721 gtk_widget_show_all (combo_box->priv->button);
1723 if (combo_box->priv->cell_view)
1725 combo_box->priv->cell_view_frame = gtk_frame_new (NULL);
1726 gtk_widget_set_parent (combo_box->priv->cell_view_frame,
1727 GTK_BIN (combo_box)->child->parent);
1728 gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
1731 g_object_set (G_OBJECT (combo_box->priv->cell_view),
1732 "background", "white",
1733 "background_set", TRUE,
1736 gtk_widget_show (combo_box->priv->cell_view_frame);
1739 combo_box->priv->tree_view = gtk_tree_view_new ();
1740 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1741 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1742 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view),
1745 g_signal_connect (combo_box->priv->tree_view, "button_press_event",
1746 G_CALLBACK (gtk_combo_box_list_button_pressed),
1748 g_signal_connect (combo_box->priv->tree_view, "button_release_event",
1749 G_CALLBACK (gtk_combo_box_list_button_released),
1751 g_signal_connect (combo_box->priv->tree_view, "key_press_event",
1752 G_CALLBACK (gtk_combo_box_list_key_press),
1755 combo_box->priv->column = gtk_tree_view_column_new ();
1756 gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view),
1757 combo_box->priv->column);
1759 /* set the models */
1760 gtk_combo_box_set_model_internal (combo_box);
1763 for (i = combo_box->priv->cells; i; i = i->next)
1766 ComboCellInfo *info = (ComboCellInfo *)i->data;
1768 if (info->pack == GTK_PACK_START)
1769 gtk_tree_view_column_pack_start (combo_box->priv->column,
1770 info->cell, info->expand);
1771 else if (info->pack == GTK_PACK_END)
1772 gtk_tree_view_column_pack_end (combo_box->priv->column,
1773 info->cell, info->expand);
1775 for (j = info->attributes; j; j = j->next->next)
1777 gtk_tree_view_column_add_attribute (combo_box->priv->column,
1780 GPOINTER_TO_INT (j->next->data));
1784 if (combo_box->priv->active_item != -1)
1788 path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1);
1791 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view),
1793 gtk_tree_path_free (path);
1797 /* set sample/popup widgets */
1798 gtk_combo_box_set_popup_widget (GTK_COMBO_BOX (combo_box),
1799 combo_box->priv->tree_view);
1801 gtk_widget_show (combo_box->priv->tree_view);
1805 gtk_combo_box_list_destroy (GtkComboBox *combo_box)
1807 /* disconnect signals */
1808 gtk_combo_box_unset_model (combo_box);
1810 g_signal_handlers_disconnect_matched (combo_box->priv->tree_view,
1811 G_SIGNAL_MATCH_DATA,
1812 0, 0, NULL, NULL, combo_box);
1813 g_signal_handlers_disconnect_matched (combo_box->priv->button,
1814 G_SIGNAL_MATCH_DATA,
1816 gtk_combo_box_list_button_pressed,
1819 /* destroy things (unparent will kill the latest ref from us)
1820 * last unref on button will destroy the arrow
1822 gtk_widget_unparent (combo_box->priv->button);
1824 if (combo_box->priv->cell_view)
1826 g_object_set (G_OBJECT (combo_box->priv->cell_view),
1827 "background_set", FALSE,
1830 gtk_widget_unparent (combo_box->priv->cell_view_frame);
1833 gtk_widget_destroy (combo_box->priv->tree_view);
1834 combo_box->priv->tree_view = NULL;
1835 combo_box->priv->popup_widget = NULL;
1840 gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box)
1842 if (GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view))
1843 gtk_grab_remove (combo_box->priv->tree_view);
1845 if (GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window))
1847 gtk_grab_remove (combo_box->priv->popup_window);
1848 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1853 gtk_combo_box_list_button_pressed (GtkWidget *widget,
1854 GdkEventButton *event,
1857 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1859 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1861 if (ewidget == combo_box->priv->tree_view)
1864 if ((ewidget != combo_box->priv->button) ||
1865 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1868 gtk_combo_box_popup (combo_box);
1870 gtk_grab_add (combo_box->priv->popup_window);
1871 gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE,
1872 GDK_BUTTON_PRESS_MASK |
1873 GDK_BUTTON_RELEASE_MASK |
1874 GDK_POINTER_MOTION_MASK,
1875 NULL, NULL, GDK_CURRENT_TIME);
1877 gtk_grab_add (combo_box->priv->tree_view);
1879 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
1882 combo_box->priv->popup_in_progress = TRUE;
1888 gtk_combo_box_list_button_released (GtkWidget *widget,
1889 GdkEventButton *event,
1893 GtkTreePath *path = NULL;
1895 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1897 gboolean popup_in_progress = FALSE;
1899 GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1901 if (combo_box->priv->popup_in_progress)
1903 popup_in_progress = TRUE;
1904 combo_box->priv->popup_in_progress = FALSE;
1907 if (ewidget != combo_box->priv->tree_view)
1909 if (ewidget == combo_box->priv->button &&
1910 !popup_in_progress &&
1911 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1913 gtk_combo_box_list_remove_grabs (combo_box);
1914 gtk_combo_box_popdown (combo_box);
1918 /* released outside treeview */
1919 if (ewidget != combo_box->priv->button)
1921 gtk_combo_box_list_remove_grabs (combo_box);
1922 gtk_combo_box_popdown (combo_box);
1931 gtk_combo_box_list_remove_grabs (combo_box);
1933 /* select something cool */
1934 ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
1940 return TRUE; /* clicked outside window? */
1942 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1943 gtk_combo_box_popdown (combo_box);
1945 gtk_tree_path_free (path);
1951 gtk_combo_box_list_key_press (GtkWidget *widget,
1955 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1957 if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
1958 event->keyval == GDK_space || event->keyval == GDK_KP_Space) ||
1959 event->keyval == GDK_Escape)
1961 if (event->keyval != GDK_Escape)
1965 GtkTreeModel *model = NULL;
1966 GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1968 ret = gtk_tree_selection_get_selected (sel, &model, &iter);
1973 path = gtk_tree_model_get_path (model, &iter);
1976 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1977 gtk_tree_path_free (path);
1982 /* reset active item -- this is incredibly lame and ugly */
1983 gtk_combo_box_set_active (combo_box,
1984 gtk_combo_box_get_active (combo_box));
1986 gtk_combo_box_list_remove_grabs (combo_box);
1987 gtk_combo_box_popdown (combo_box);
1996 gtk_combo_box_list_row_changed (GtkTreeModel *model,
2001 GtkComboBox *combo_box = GTK_COMBO_BOX (data);
2004 width = gtk_combo_box_calc_requested_width (combo_box, path);
2006 if (width > combo_box->priv->width)
2008 gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
2009 gtk_widget_queue_resize (combo_box->priv->cell_view);
2010 combo_box->priv->width = width;
2015 * GtkCellLayout implementation
2018 gtk_combo_box_cell_layout_pack_start (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_START;
2034 combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
2036 if (combo_box->priv->cell_view)
2037 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2040 if (combo_box->priv->column)
2041 gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand);
2043 menu = combo_box->priv->popup_widget;
2044 if (GTK_IS_MENU (menu))
2048 list = gtk_container_get_children (GTK_CONTAINER (menu));
2049 for (i = list; i; i = i->next)
2053 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2054 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2056 view = GTK_CELL_VIEW (i->data);
2058 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand);
2065 gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout,
2066 GtkCellRenderer *cell,
2069 ComboCellInfo *info;
2070 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2073 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2074 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2076 info = g_new0 (ComboCellInfo, 1);
2078 info->expand = expand;
2079 info->pack = GTK_PACK_END;
2081 if (combo_box->priv->cell_view)
2082 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2085 if (combo_box->priv->column)
2086 gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand);
2088 menu = combo_box->priv->popup_widget;
2089 if (GTK_IS_MENU (menu))
2093 list = gtk_container_get_children (GTK_CONTAINER (menu));
2094 for (i = list; i; i = i->next)
2098 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2099 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2101 view = GTK_CELL_VIEW (i->data);
2103 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand);
2110 gtk_combo_box_cell_layout_clear (GtkCellLayout *layout)
2113 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2115 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2117 if (combo_box->priv->cell_view)
2118 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view));
2120 if (combo_box->priv->column)
2121 gtk_tree_view_column_clear (combo_box->priv->column);
2123 menu = combo_box->priv->popup_widget;
2124 if (GTK_IS_MENU (menu))
2128 list = gtk_container_get_children (GTK_CONTAINER (menu));
2129 for (i = list; i; i = i->next)
2133 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2134 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2136 view = GTK_CELL_VIEW (i->data);
2138 gtk_cell_layout_clear (GTK_CELL_LAYOUT (view));
2145 gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout,
2146 GtkCellRenderer *cell,
2147 const gchar *attribute,
2150 ComboCellInfo *info;
2151 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2154 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2155 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2157 info = gtk_combo_box_get_cell_info (combo_box, cell);
2159 info->attributes = g_slist_prepend (info->attributes,
2160 GINT_TO_POINTER (column));
2161 info->attributes = g_slist_prepend (info->attributes,
2162 g_strdup (attribute));
2164 if (combo_box->priv->cell_view)
2165 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2166 cell, attribute, column);
2168 if (combo_box->priv->column)
2169 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column),
2170 cell, attribute, column);
2172 menu = combo_box->priv->popup_widget;
2173 if (GTK_IS_MENU (menu))
2177 list = gtk_container_get_children (GTK_CONTAINER (menu));
2178 for (i = list; i; i = i->next)
2182 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2183 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2185 view = GTK_CELL_VIEW (i->data);
2187 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell,
2193 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2197 gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout,
2198 GtkCellRenderer *cell,
2199 GtkCellLayoutDataFunc func,
2201 GDestroyNotify destroy)
2203 ComboCellInfo *info;
2204 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2207 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2209 info = gtk_combo_box_get_cell_info (combo_box, cell);
2210 g_return_if_fail (info != NULL);
2214 GDestroyNotify d = info->destroy;
2216 info->destroy = NULL;
2217 d (info->func_data);
2221 info->func_data = func_data;
2222 info->destroy = destroy;
2224 if (combo_box->priv->cell_view)
2225 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL);
2227 if (combo_box->priv->column)
2228 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL);
2230 menu = combo_box->priv->popup_widget;
2231 if (GTK_IS_MENU (menu))
2235 list = gtk_container_get_children (GTK_CONTAINER (menu));
2236 for (i = list; i; i = i->next)
2240 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2241 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2243 view = GTK_CELL_VIEW (i->data);
2245 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell,
2246 func, func_data, NULL);
2251 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2255 gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout,
2256 GtkCellRenderer *cell)
2258 ComboCellInfo *info;
2259 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2263 g_return_if_fail (GTK_IS_COMBO_BOX (layout));
2264 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2266 info = gtk_combo_box_get_cell_info (combo_box, cell);
2267 g_return_if_fail (info != NULL);
2269 list = info->attributes;
2270 while (list && list->next)
2272 g_free (list->data);
2273 list = list->next->next;
2275 g_slist_free (list);
2277 info->attributes = NULL;
2279 if (combo_box->priv->cell_view)
2280 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell);
2282 if (combo_box->priv->column)
2283 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell);
2285 menu = combo_box->priv->popup_widget;
2286 if (GTK_IS_MENU (menu))
2290 list = gtk_container_get_children (GTK_CONTAINER (menu));
2291 for (i = list; i; i = i->next)
2295 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2296 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2298 view = GTK_CELL_VIEW (i->data);
2300 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell);
2305 gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2309 gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout,
2310 GtkCellRenderer *cell,
2313 ComboCellInfo *info;
2314 GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2318 g_return_if_fail (GTK_IS_COMBO_BOX (layout));
2319 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2321 info = gtk_combo_box_get_cell_info (combo_box, cell);
2323 g_return_if_fail (info != NULL);
2324 g_return_if_fail (position >= 0);
2326 link = g_slist_find (combo_box->priv->cells, info);
2328 g_return_if_fail (link != NULL);
2330 combo_box->priv->cells = g_slist_remove_link (combo_box->priv->cells, link);
2331 combo_box->priv->cells = g_slist_insert (combo_box->priv->cells, info,
2334 if (combo_box->priv->cell_view)
2335 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2338 if (combo_box->priv->column)
2339 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->column),
2342 menu = combo_box->priv->popup_widget;
2343 if (GTK_IS_MENU (menu))
2347 list = gtk_container_get_children (GTK_CONTAINER (menu));
2348 for (i = list; i; i = i->next)
2352 if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2353 view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2355 view = GTK_CELL_VIEW (i->data);
2357 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (view), cell, position);
2362 gtk_widget_queue_draw (GTK_WIDGET (combo_box));
2370 * gtk_combo_box_new:
2372 * Creates a new empty #GtkComboBox.
2374 * Return value: A new #GtkComboBox.
2379 gtk_combo_box_new (void)
2381 return GTK_WIDGET (g_object_new (GTK_TYPE_COMBO_BOX, NULL));
2385 * gtk_combo_box_new_with_model:
2386 * @model: A #GtkTreeModel.
2388 * Creates a new #GtkComboBox with the model initialized to @model.
2390 * Return value: A new #GtkComboBox.
2395 gtk_combo_box_new_with_model (GtkTreeModel *model)
2397 GtkComboBox *combo_box;
2399 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
2401 combo_box = GTK_COMBO_BOX (g_object_new (GTK_TYPE_COMBO_BOX,
2405 return GTK_WIDGET (combo_box);
2409 * gtk_combo_box_set_wrap_width:
2410 * @combo_box: A #GtkComboBox.
2411 * @width: Preferred number of columns.
2413 * Sets the wrap width of @combo_box to be @width. The wrap width is basically
2414 * the preferred number of columns when you want to the popup to be layed out
2420 gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
2423 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2424 g_return_if_fail (width > 0);
2426 combo_box->priv->wrap_width = width;
2428 gtk_combo_box_relayout (combo_box);
2432 * gtk_combo_box_set_row_span_column:
2433 * @combo_box: A #GtkComboBox.
2434 * @row_span: A column in the model passed during construction.
2436 * Sets the column with row span information for @combo_box to be @row_span.
2437 * The row span column contains integers which indicate how many rows
2438 * an item should span.
2443 gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
2448 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2450 col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2451 g_return_if_fail (row_span >= 0 && row_span < col);
2453 combo_box->priv->row_column = row_span;
2455 gtk_combo_box_relayout (combo_box);
2459 * gtk_combo_box_set_column_span_column:
2460 * @combo_box: A #GtkComboBox.
2461 * @column_span: A column in the model passed during construction.
2463 * Sets the column with column span information for @combo_box to be
2464 * @column_span. The column span column contains integers which indicate
2465 * how many columns an item should span.
2470 gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
2475 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2477 col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2478 g_return_if_fail (column_span >= 0 && column_span < col);
2480 combo_box->priv->col_column = column_span;
2482 gtk_combo_box_relayout (combo_box);
2486 * gtk_combo_box_get_active:
2487 * @combo_box: A #GtkComboBox.
2489 * Returns the index of the currently active item, or -1 if there's no
2492 * Return value: An integer which is the index of the currently active item, or
2493 * -1 if there's no active item.
2498 gtk_combo_box_get_active (GtkComboBox *combo_box)
2500 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
2502 return combo_box->priv->active_item;
2506 * gtk_combo_box_set_active:
2507 * @combo_box: A #GtkComboBox.
2508 * @index: An index in the model passed during construction, or -1 to have
2511 * Sets the active item of @combo_box to be the item at @index.
2516 gtk_combo_box_set_active (GtkComboBox *combo_box,
2521 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2522 /* -1 means "no item selected" */
2523 g_return_if_fail (index >= -1);
2525 if (combo_box->priv->active_item == index)
2528 combo_box->priv->active_item = index;
2532 if (combo_box->priv->tree_view)
2533 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)));
2536 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2538 if (GTK_IS_MENU (menu))
2539 gtk_menu_set_active (menu, -1);
2542 if (combo_box->priv->cell_view)
2543 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
2547 path = gtk_tree_path_new_from_indices (index, -1);
2549 if (combo_box->priv->tree_view)
2550 gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE);
2553 GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2555 if (GTK_IS_MENU (menu))
2556 gtk_menu_set_active (GTK_MENU (menu), index);
2559 if (combo_box->priv->cell_view)
2560 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path);
2562 gtk_tree_path_free (path);
2565 g_signal_emit_by_name (combo_box, "changed", NULL, NULL);
2570 * gtk_combo_box_get_active_iter:
2571 * @combo_box: A #GtkComboBox
2572 * @iter: The uninitialized #GtkTreeIter.
2574 * Set @iter to point to the current active item, if it exists.
2576 * Return value: %TRUE, if @iter was set
2581 gtk_combo_box_get_active_iter (GtkComboBox *combo_box,
2588 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
2590 active = gtk_combo_box_get_active (combo_box);
2594 path = gtk_tree_path_new_from_indices (active, -1);
2595 retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box),
2597 gtk_tree_path_free (path);
2603 * gtk_combo_box_set_active_iter:
2604 * @combo_box: A #GtkComboBox
2605 * @iter: The #GtkTreeIter.
2607 * Sets the current active item to be the one referenced by @iter.
2608 * @iter must correspond to a path of depth one.
2613 gtk_combo_box_set_active_iter (GtkComboBox *combo_box,
2618 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2620 path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
2621 g_return_if_fail (path != NULL);
2622 g_return_if_fail (gtk_tree_path_get_depth (path) == 1);
2624 gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
2625 gtk_tree_path_free (path);
2629 * gtk_combo_box_set_model:
2630 * @combo_box: A #GtkComboBox.
2631 * @model: A #GtkTreeModel.
2633 * Sets the model used by @combo_box to be @model. Will unset a
2634 * previously set model (if applicable).
2639 gtk_combo_box_set_model (GtkComboBox *combo_box,
2640 GtkTreeModel *model)
2642 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2643 g_return_if_fail (GTK_IS_TREE_MODEL (model));
2645 if (combo_box->priv->model)
2647 gtk_combo_box_unset_model (combo_box);
2648 g_object_unref (G_OBJECT (combo_box->priv->model));
2651 combo_box->priv->model = model;
2652 g_object_ref (G_OBJECT (combo_box->priv->model));
2654 gtk_combo_box_set_model_internal (combo_box);
2655 if (!combo_box->priv->tree_view && combo_box->priv->popup_widget)
2656 gtk_combo_box_menu_fill (combo_box);
2658 if (combo_box->priv->cell_view)
2659 gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
2660 combo_box->priv->model);
2664 * gtk_combo_box_get_model
2665 * @combo_box: A #GtkComboBox.
2667 * Returns the #GtkTreeModel which is acting as data source for @combo_box.
2669 * Return value: A #GtkTreeModel which was passed during construction.
2674 gtk_combo_box_get_model (GtkComboBox *combo_box)
2676 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
2678 return combo_box->priv->model;
2682 /* convenience API for simple text combos */
2685 * gtk_combo_box_new_text:
2687 * Convenience function which constructs a new text combo box, which is a
2688 * #GtkComboBox just displaying strings. If you use this function to create
2689 * a text combo box, you only want to manipulate it's data source with the
2690 * following convenience functions: gtk_combo_box_append_text(),
2691 * gtk_combo_box_insert_text() and gtk_combo_box_prepend_text().
2693 * Return value: A new text combo box.
2698 gtk_combo_box_new_text (void)
2700 GtkWidget *combo_box;
2701 GtkCellRenderer *cell;
2702 GtkListStore *store;
2704 store = gtk_list_store_new (1, G_TYPE_STRING);
2706 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
2708 cell = gtk_cell_renderer_text_new ();
2709 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
2710 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
2718 * gtk_combo_box_append_text:
2719 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2722 * Appends @string to the list of strings stored in @combo_box. Note that
2723 * you can only use this function with combo boxes constructed with
2724 * gtk_combo_box_new_text().
2729 gtk_combo_box_append_text (GtkComboBox *combo_box,
2733 GtkListStore *store;
2735 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2736 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2737 g_return_if_fail (text != NULL);
2739 store = GTK_LIST_STORE (combo_box->priv->model);
2741 gtk_list_store_append (store, &iter);
2742 gtk_list_store_set (store, &iter, 0, text, -1);
2746 * gtk_combo_box_insert_text:
2747 * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2748 * @position: An index to insert @text.
2751 * Inserts @string at @position in the list of strings stored in @combo_box.
2752 * Note that you can only use this function with combo boxes constructed
2753 * with gtk_combo_box_new_text().
2758 gtk_combo_box_insert_text (GtkComboBox *combo_box,
2763 GtkListStore *store;
2765 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2766 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2767 g_return_if_fail (position >= 0);
2768 g_return_if_fail (text != NULL);
2770 store = GTK_LIST_STORE (combo_box->priv->model);
2772 gtk_list_store_insert (store, &iter, position);
2773 gtk_list_store_set (store, &iter, 0, text, -1);
2777 * gtk_combo_box_prepend_text:
2778 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2781 * Prepends @string to the list of strings stored in @combo_box. Note that
2782 * you can only use this function with combo boxes constructed with
2783 * gtk_combo_box_new_text().
2788 gtk_combo_box_prepend_text (GtkComboBox *combo_box,
2792 GtkListStore *store;
2794 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2795 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2796 g_return_if_fail (text != NULL);
2798 store = GTK_LIST_STORE (combo_box->priv->model);
2800 gtk_list_store_prepend (store, &iter);
2801 gtk_list_store_set (store, &iter, 0, text, -1);
2805 * gtk_combo_box_remove_text:
2806 * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2807 * @position: Index of the item to remove.
2809 * Removes the string at @position from @combo_box. Note that you can only use
2810 * this function with combo boxes constructed with gtk_combo_box_new_text().
2815 gtk_combo_box_remove_text (GtkComboBox *combo_box,
2819 GtkListStore *store;
2821 g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2822 g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2823 g_return_if_fail (position >= 0);
2825 store = GTK_LIST_STORE (combo_box->priv->model);
2827 if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter,
2829 gtk_list_store_remove (store, &iter);
2834 gtk_combo_box_mnemonic_activate (GtkWidget *widget,
2835 gboolean group_cycling)
2837 GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
2839 gtk_widget_grab_focus (combo_box->priv->button);
2846 gtk_combo_box_finalize (GObject *object)
2848 GtkComboBox *combo_box = GTK_COMBO_BOX (object);
2850 if (GTK_IS_MENU (combo_box->priv->popup_widget))
2851 gtk_combo_box_menu_destroy (combo_box);
2853 if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
2854 gtk_combo_box_list_destroy (combo_box);
2856 if (combo_box->priv->popup_window)
2857 gtk_widget_destroy (combo_box->priv->popup_window);
2859 if (combo_box->priv->model)
2860 g_object_unref (combo_box->priv->model);
2862 g_slist_foreach (combo_box->priv->cells, (GFunc)g_free, NULL);
2863 g_slist_free (combo_box->priv->cells);
2865 G_OBJECT_CLASS (parent_class)->finalize (object);