]> Pileus Git - ~andy/gtk/blob - gtk/gtkcombobox.c
move function to a somewhat more logical place,
[~andy/gtk] / gtk / gtkcombobox.c
1 /* gtkcombobox.c
2  * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #include "gtkcombobox.h"
21 #include "gtkcelllayout.h"
22 #include "gtkcellview.h"
23 #include "gtkcellviewmenuitem.h"
24
25 #include "gtktreeselection.h"
26 #include "gtkframe.h"
27 #include "gtktogglebutton.h"
28 #include "gtkvseparator.h"
29 #include "gtkarrow.h"
30 #include "gtkmenu.h"
31 #include "gtkmain.h"
32 #include "gtkeventbox.h"
33 #include "gtkcellrenderertext.h"
34 #include "gtkbindings.h"
35 #include "gtkliststore.h"
36 #include "gtkwindow.h"
37
38 #include <gdk/gdkkeysyms.h>
39
40 #include <gobject/gvaluecollector.h>
41
42 #include <string.h>
43 #include <stdarg.h>
44
45 #include "gtkmarshalers.h"
46 #include "gtkintl.h"
47
48
49 /* WELCOME, to THE house of evil code */
50
51
52 typedef struct _ComboCellInfo ComboCellInfo;
53 struct _ComboCellInfo
54 {
55   GtkCellRenderer *cell;
56   GSList *attributes;
57
58   GtkCellLayoutDataFunc func;
59   gpointer func_data;
60   GDestroyNotify destroy;
61
62   guint expand : 1;
63   guint pack : 1;
64 };
65
66 #define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate))
67
68 struct _GtkComboBoxPrivate
69 {
70   GtkTreeModel *model;
71
72   gint col_column;
73   gint row_column;
74
75   gint wrap_width;
76
77   gint active_item;
78
79   GtkWidget *tree_view;
80   GtkTreeViewColumn *column;
81
82   GtkWidget *cell_view;
83
84   GtkWidget *hbox;
85   GtkWidget *cell_view_frame;
86
87   GtkWidget *button;
88   GtkWidget *arrow;
89   GtkWidget *separator;
90
91   GtkWidget *popup_widget;
92   GtkWidget *popup_window;
93   GtkWidget *popup_frame;
94
95   guint inserted_id;
96   guint deleted_id;
97
98   gint width;
99   GSList *cells;
100
101   guint changed_id;
102
103   guint popup_in_progress : 1;
104 };
105
106 enum {
107   CHANGED,
108   LAST_SIGNAL
109 };
110
111 enum {
112   PROP_0,
113   PROP_MODEL,
114   PROP_WRAP_WIDTH,
115   PROP_ROW_SPAN_COLUMN,
116   PROP_COLUMN_SPAN_COLUMN,
117   PROP_ACTIVE
118 };
119
120 static GtkBinClass *parent_class = NULL;
121 static guint combo_box_signals[LAST_SIGNAL] = {0,};
122
123 #define BONUS_PADDING 4
124
125
126 /* common */
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);
130
131 static void     gtk_combo_box_set_property         (GObject         *object,
132                                                     guint            prop_id,
133                                                     const GValue    *value,
134                                                     GParamSpec      *spec);
135 static void     gtk_combo_box_get_property         (GObject         *object,
136                                                     guint            prop_id,
137                                                     GValue          *value,
138                                                     GParamSpec      *spec);
139
140 static void     gtk_combo_box_style_set            (GtkWidget       *widget,
141                                                     GtkStyle        *previous_style,
142                                                     gpointer         data);
143 static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
144                                                     gpointer         data);
145 static void     gtk_combo_box_add                  (GtkContainer    *container,
146                                                     GtkWidget       *widget);
147
148 static ComboCellInfo *gtk_combo_box_get_cell_info  (GtkComboBox      *combo_box,
149                                                     GtkCellRenderer  *cell);
150
151 static void     gtk_combo_box_menu_show            (GtkWidget        *menu,
152                                                     gpointer          user_data);
153 static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
154                                                     gpointer          user_data);
155
156 static void     gtk_combo_box_set_popup_widget     (GtkComboBox      *combo_box,
157                                                     GtkWidget        *popup);
158 static void     gtk_combo_box_menu_position        (GtkMenu          *menu,
159                                                     gint             *x,
160                                                     gint             *y,
161                                                     gint             *push_in,
162                                                     gpointer          user_data);
163 static void     gtk_combo_box_popup                (GtkComboBox      *combo_box);
164 static void     gtk_combo_box_popdown              (GtkComboBox      *combo_box);
165
166 static gint     gtk_combo_box_calc_requested_width (GtkComboBox      *combo_box,
167                                                     GtkTreePath      *path);
168 static void     gtk_combo_box_remeasure            (GtkComboBox      *combo_box);
169
170 static void     gtk_combo_box_unset_model          (GtkComboBox      *combo_box);
171 static void     gtk_combo_box_set_model_internal   (GtkComboBox      *combo_box);
172
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);
185
186 /* list */
187 static void     gtk_combo_box_list_setup           (GtkComboBox      *combo_box);
188 static void     gtk_combo_box_list_destroy         (GtkComboBox      *combo_box);
189
190 static gboolean gtk_combo_box_list_button_released (GtkWidget        *widget,
191                                                     GdkEventButton   *event,
192                                                     gpointer          data);
193 static gboolean gtk_combo_box_list_key_press       (GtkWidget        *widget,
194                                                     GdkEventKey      *event,
195                                                     gpointer          data);
196 static gboolean gtk_combo_box_list_button_pressed  (GtkWidget        *widget,
197                                                     GdkEventButton   *event,
198                                                     gpointer          data);
199
200 static void     gtk_combo_box_list_row_changed     (GtkTreeModel     *model,
201                                                     GtkTreePath      *path,
202                                                     GtkTreeIter      *iter,
203                                                     gpointer          data);
204
205 /* menu */
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);
210
211 static void     gtk_combo_box_item_get_size        (GtkComboBox      *combo_box,
212                                                     gint              index,
213                                                     gint             *cols,
214                                                     gint             *rows);
215 static void     gtk_combo_box_relayout_item        (GtkComboBox      *combo_box,
216                                                     gint              index);
217 static void     gtk_combo_box_relayout             (GtkComboBox      *combo_box);
218
219 static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
220                                                     GdkEventButton   *event,
221                                                     gpointer          user_data);
222 static void     gtk_combo_box_menu_item_activate   (GtkWidget        *item,
223                                                     gpointer          user_data);
224 static void     gtk_combo_box_menu_row_inserted    (GtkTreeModel     *model,
225                                                     GtkTreePath      *path,
226                                                     GtkTreeIter      *iter,
227                                                     gpointer          user_data);
228 static void     gtk_combo_box_menu_row_deleted     (GtkTreeModel     *model,
229                                                     GtkTreePath      *path,
230                                                     gpointer          user_data);
231 static void     gtk_combo_box_menu_row_changed     (GtkTreeModel     *model,
232                                                     GtkTreePath      *path,
233                                                     GtkTreeIter      *iter,
234                                                     gpointer          data);
235
236 /* cell layout */
237 static void     gtk_combo_box_cell_layout_pack_start         (GtkCellLayout         *layout,
238                                                               GtkCellRenderer       *cell,
239                                                               gboolean               expand);
240 static void     gtk_combo_box_cell_layout_pack_end           (GtkCellLayout         *layout,
241                                                               GtkCellRenderer       *cell,
242                                                               gboolean               expand);
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,
247                                                               gint                   column);
248 static void     gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
249                                                               GtkCellRenderer       *cell,
250                                                               GtkCellLayoutDataFunc  func,
251                                                               gpointer               func_data,
252                                                               GDestroyNotify         destroy);
253 static void     gtk_combo_box_cell_layout_clear_attributes   (GtkCellLayout         *layout,
254                                                               GtkCellRenderer       *cell);
255
256
257 GType
258 gtk_combo_box_get_type (void)
259 {
260   static GType combo_box_type = 0;
261
262   if (!combo_box_type)
263     {
264       static const GTypeInfo combo_box_info =
265         {
266           sizeof (GtkComboBoxClass),
267           NULL, /* base_init */
268           NULL, /* base_finalize */
269           (GClassInitFunc) gtk_combo_box_class_init,
270           NULL, /* class_finalize */
271           NULL, /* class_data */
272           sizeof (GtkComboBox),
273           0,
274           (GInstanceInitFunc) gtk_combo_box_init
275         };
276
277       static const GInterfaceInfo cell_layout_info =
278         {
279           (GInterfaceInitFunc) gtk_combo_box_cell_layout_init,
280           NULL,
281           NULL
282         };
283
284       combo_box_type = g_type_register_static (GTK_TYPE_BIN,
285                                                "GtkComboBox",
286                                                &combo_box_info,
287                                                0);
288
289       g_type_add_interface_static (combo_box_type,
290                                    GTK_TYPE_CELL_LAYOUT,
291                                    &cell_layout_info);
292     }
293
294   return combo_box_type;
295 }
296
297 /* common */
298 static void
299 gtk_combo_box_class_init (GtkComboBoxClass *klass)
300 {
301   GObjectClass *object_class;
302   GtkBindingSet *binding_set;
303   GtkContainerClass *container_class;
304   GtkWidgetClass *widget_class;
305
306   binding_set = gtk_binding_set_by_class (klass);
307
308   container_class = (GtkContainerClass *)klass;
309   container_class->forall = gtk_combo_box_forall;
310   container_class->add = gtk_combo_box_add;
311
312   widget_class = (GtkWidgetClass *)klass;
313   widget_class->size_allocate = gtk_combo_box_size_allocate;
314   widget_class->size_request = gtk_combo_box_size_request;
315   widget_class->expose_event = gtk_combo_box_expose_event;
316   widget_class->scroll_event = gtk_combo_box_scroll_event;
317
318   object_class = (GObjectClass *)klass;
319   object_class->set_property = gtk_combo_box_set_property;
320   object_class->get_property = gtk_combo_box_get_property;
321
322   parent_class = g_type_class_peek_parent (klass);
323
324   /* signals */
325   combo_box_signals[CHANGED] =
326     g_signal_new ("changed",
327                   G_OBJECT_CLASS_TYPE (klass),
328                   G_SIGNAL_RUN_LAST,
329                   G_STRUCT_OFFSET (GtkComboBoxClass, changed),
330                   NULL, NULL,
331                   g_cclosure_marshal_VOID__VOID,
332                   G_TYPE_NONE, 0);
333
334   /* properties */
335   g_object_class_install_property (object_class,
336                                    PROP_MODEL,
337                                    g_param_spec_object ("model",
338                                                         _("ComboBox model"),
339                                                         _("The model for the combo box"),
340                                                         GTK_TYPE_TREE_MODEL,
341                                                         G_PARAM_READWRITE));
342
343   g_object_class_install_property (object_class,
344                                    PROP_WRAP_WIDTH,
345                                    g_param_spec_int ("wrap_width",
346                                                      _("Wrap width"),
347                                                      _("Wrap width for layouting the items in a grid"),
348                                                      0,
349                                                      G_MAXINT,
350                                                      0,
351                                                      G_PARAM_READWRITE));
352
353   g_object_class_install_property (object_class,
354                                    PROP_ROW_SPAN_COLUMN,
355                                    g_param_spec_int ("row_span_column",
356                                                      _("Row span column"),
357                                                      _("TreeModel column containing the row span values"),
358                                                      0,
359                                                      G_MAXINT,
360                                                      0,
361                                                      G_PARAM_READWRITE));
362
363   g_object_class_install_property (object_class,
364                                    PROP_COLUMN_SPAN_COLUMN,
365                                    g_param_spec_int ("column_span_column",
366                                                      _("Column span column"),
367                                                      _("TreeModel column containing the column span values"),
368                                                      0,
369                                                      G_MAXINT,
370                                                      0,
371                                                      G_PARAM_READWRITE));
372
373   g_object_class_install_property (object_class,
374                                    PROP_ACTIVE,
375                                    g_param_spec_int ("active",
376                                                      _("Active item"),
377                                                      _("The item which is currently active"),
378                                                      0,
379                                                      G_MAXINT,
380                                                      0,
381                                                      G_PARAM_READWRITE));
382
383   gtk_widget_class_install_style_property (widget_class,
384                                            g_param_spec_boolean ("appearance",
385                                                                  _("ComboBox appareance"),
386                                                                  _("ComboBox appearance, where TRUE means Windows-style."),
387                                                                  FALSE,
388                                                                  G_PARAM_READWRITE));
389
390   g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
391 }
392
393 static void
394 gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
395 {
396   iface->pack_start = gtk_combo_box_cell_layout_pack_start;
397   iface->pack_end = gtk_combo_box_cell_layout_pack_end;
398   iface->clear = gtk_combo_box_cell_layout_clear;
399   iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
400   iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
401   iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
402 }
403
404 static void
405 gtk_combo_box_init (GtkComboBox *combo_box)
406 {
407   combo_box->priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
408
409   g_signal_connect (combo_box, "style_set",
410                     G_CALLBACK (gtk_combo_box_style_set), NULL);
411
412   combo_box->priv->cell_view = gtk_cell_view_new ();
413   gtk_container_add (GTK_CONTAINER (combo_box), combo_box->priv->cell_view);
414   gtk_widget_show (combo_box->priv->cell_view);
415
416   combo_box->priv->width = 0;
417   combo_box->priv->wrap_width = 0;
418
419   combo_box->priv->active_item = -1;
420   combo_box->priv->col_column = -1;
421   combo_box->priv->row_column = -1;
422 }
423
424 static void
425 gtk_combo_box_set_property (GObject      *object,
426                             guint         prop_id,
427                             const GValue *value,
428                             GParamSpec   *pspec)
429 {
430   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
431
432   switch (prop_id)
433     {
434       case PROP_MODEL:
435         gtk_combo_box_set_model (combo_box, g_value_get_object (value));
436         break;
437
438       case PROP_WRAP_WIDTH:
439         gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
440         break;
441
442       case PROP_ROW_SPAN_COLUMN:
443         gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
444         break;
445
446       case PROP_COLUMN_SPAN_COLUMN:
447         gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
448         break;
449
450       case PROP_ACTIVE:
451         gtk_combo_box_set_active (combo_box, g_value_get_int (value));
452         break;
453
454       default:
455         break;
456     }
457 }
458
459 static void
460 gtk_combo_box_get_property (GObject    *object,
461                             guint       prop_id,
462                             GValue     *value,
463                             GParamSpec *pspec)
464 {
465   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
466
467   switch (prop_id)
468     {
469       case PROP_MODEL:
470         g_value_set_object (value, combo_box->priv->model);
471         break;
472
473       case PROP_WRAP_WIDTH:
474         g_value_set_int (value, combo_box->priv->wrap_width);
475         break;
476
477       case PROP_ROW_SPAN_COLUMN:
478         g_value_set_int (value, combo_box->priv->row_column);
479         break;
480
481       case PROP_COLUMN_SPAN_COLUMN:
482         g_value_set_int (value, combo_box->priv->col_column);
483         break;
484
485       case PROP_ACTIVE:
486         g_value_set_int (value, gtk_combo_box_get_active (combo_box));
487         break;
488
489       default:
490         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
491         break;
492     }
493 }
494
495 static void
496 gtk_combo_box_style_set (GtkWidget *widget,
497                          GtkStyle  *previous_style,
498                          gpointer   data)
499 {
500   gboolean appearance;
501   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
502
503   gtk_widget_queue_resize (widget);
504
505   /* if wrap_width > 0, then we are in grid-mode and forced to use
506    * unix style
507    */
508   if (combo_box->priv->wrap_width)
509     return;
510
511   gtk_widget_style_get (widget,
512                         "appearance", &appearance,
513                         NULL);
514
515   /* TRUE is windows style */
516   if (appearance)
517     {
518       if (GTK_IS_MENU (combo_box->priv->popup_widget))
519         gtk_combo_box_menu_destroy (combo_box);
520       gtk_combo_box_list_setup (combo_box);
521     }
522   else
523     {
524       if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
525         gtk_combo_box_list_destroy (combo_box);
526       gtk_combo_box_menu_setup (combo_box, TRUE);
527     }
528 }
529
530 static void
531 gtk_combo_box_button_toggled (GtkWidget *widget,
532                               gpointer   data)
533 {
534   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
535
536   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
537     {
538       if (!combo_box->priv->popup_in_progress)
539         gtk_combo_box_popup (combo_box);
540     }
541   else
542     gtk_combo_box_popdown (combo_box);
543 }
544
545 static void
546 gtk_combo_box_add (GtkContainer *container,
547                    GtkWidget    *widget)
548 {
549   GtkComboBox *combo_box = GTK_COMBO_BOX (container);
550
551   if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent)
552     {
553       gtk_container_remove (container, combo_box->priv->cell_view);
554       (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
555     }
556   else
557     {
558       (* GTK_CONTAINER_CLASS (parent_class)->add) (container, widget);
559     }
560
561   if (combo_box->priv->cell_view &&
562       widget != combo_box->priv->cell_view)
563     {
564       /* since the cell_view was unparented, it's gone now */
565       combo_box->priv->cell_view = NULL;
566
567       if (!combo_box->priv->tree_view && combo_box->priv->separator)
568         {
569           gtk_widget_unparent (combo_box->priv->separator);
570
571           g_object_ref (G_OBJECT (combo_box->priv->arrow));
572           gtk_widget_unparent (combo_box->priv->arrow);
573           gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
574                              combo_box->priv->arrow);
575           g_object_unref (G_OBJECT (combo_box->priv->arrow));
576
577           gtk_widget_queue_resize (GTK_WIDGET (container));
578         }
579       else if (combo_box->priv->cell_view_frame)
580         {
581           gtk_widget_unparent (combo_box->priv->cell_view_frame);
582           combo_box->priv->cell_view_frame = NULL;
583         }
584     }
585 }
586
587 static ComboCellInfo *
588 gtk_combo_box_get_cell_info (GtkComboBox     *combo_box,
589                              GtkCellRenderer *cell)
590 {
591   GSList *i;
592
593   for (i = combo_box->priv->cells; i; i = i->next)
594     {
595       ComboCellInfo *info = (ComboCellInfo *)i->data;
596
597       if (info->cell == cell)
598         return info;
599     }
600
601   return NULL;
602 }
603
604 static void
605 gtk_combo_box_menu_show (GtkWidget *menu,
606                          gpointer   user_data)
607 {
608   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
609
610   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
611                                 TRUE);
612   combo_box->priv->popup_in_progress = FALSE;
613 }
614
615 static void
616 gtk_combo_box_menu_hide (GtkWidget *menu,
617                          gpointer   user_data)
618 {
619   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
620
621   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
622                                 FALSE);
623 }
624
625 static void
626 gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
627                                 GtkWidget   *popup)
628 {
629   if (GTK_IS_MENU (combo_box->priv->popup_widget))
630     combo_box->priv->popup_widget = NULL;
631   else if (combo_box->priv->popup_widget)
632     {
633       gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame),
634                             combo_box->priv->popup_widget);
635       g_object_unref (G_OBJECT (combo_box->priv->popup_widget));
636       combo_box->priv->popup_widget = NULL;
637     }
638
639   if (GTK_IS_MENU (popup))
640     {
641       if (combo_box->priv->popup_window)
642         {
643           gtk_widget_destroy (combo_box->priv->popup_window);
644           combo_box->priv->popup_window = combo_box->priv->popup_frame = NULL;
645         }
646
647       combo_box->priv->popup_widget = popup;
648
649       g_signal_connect (popup, "show",
650                         G_CALLBACK (gtk_combo_box_menu_show), combo_box);
651       g_signal_connect (popup, "hide",
652                         G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
653
654       /* FIXME: need to attach to widget? */
655     }
656   else
657     {
658       if (!combo_box->priv->popup_window)
659         {
660           combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
661
662           combo_box->priv->popup_frame = gtk_frame_new (NULL);
663           gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame),
664                                      GTK_SHADOW_NONE);
665           gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window),
666                              combo_box->priv->popup_frame);
667           gtk_widget_show (combo_box->priv->popup_frame);
668         }
669
670       gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame),
671                          popup);
672       gtk_widget_show (popup);
673       g_object_ref (G_OBJECT (popup));
674       combo_box->priv->popup_widget = popup;
675     }
676 }
677
678 static void
679 gtk_combo_box_menu_position (GtkMenu  *menu,
680                              gint     *x,
681                              gint     *y,
682                              gint     *push_in,
683                              gpointer  user_data)
684 {
685   gint sx, sy;
686   GtkWidget *child;
687   GtkRequisition req;
688   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
689
690   /* FIXME: is using the size request here broken? */
691   child = GTK_BIN (combo_box)->child;
692
693   gdk_window_get_origin (child->window, &sx, &sy);
694
695   gtk_widget_size_request (GTK_WIDGET (menu), &req);
696
697   *x = sx + child->allocation.width - req.width;
698   *y = sy + child->allocation.height;
699
700   if (GTK_WIDGET_NO_WINDOW (child))
701     {
702       *x += child->allocation.x;
703       *y += child->allocation.y;
704     }
705
706   *push_in = TRUE;
707 }
708
709 static void
710 gtk_combo_box_popup (GtkComboBox *combo_box)
711 {
712   gint x, y, width, height;
713   GtkWidget *sample;
714
715   if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
716     return;
717
718   if (GTK_IS_MENU (combo_box->priv->popup_widget))
719     {
720       if (combo_box->priv->active_item != -1)
721         {
722           GList *childs;
723
724           childs = gtk_container_get_children (GTK_CONTAINER (combo_box->priv->popup_widget));
725           gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
726                                       g_list_nth_data (childs, combo_box->priv->active_item));
727           g_list_free (childs);
728         }
729
730       gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
731                       NULL, NULL,
732                       gtk_combo_box_menu_position, combo_box,
733                       0, 0);
734       return;
735     }
736
737   /* size it */
738   sample = GTK_BIN (combo_box)->child;
739
740   width = sample->allocation.width;
741   height = sample->allocation.height;
742
743   gdk_window_get_origin (sample->window,
744                          &x, &y);
745   gtk_widget_set_size_request (combo_box->priv->popup_window,
746                                width, -1);
747
748   if (GTK_WIDGET_NO_WINDOW (sample))
749     {
750       x += sample->allocation.x;
751       y += sample->allocation.y;
752     }
753
754   gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window),
755                    x, y + height);
756
757   /* popup */
758   gtk_widget_show_all (combo_box->priv->popup_window);
759
760   gtk_widget_grab_focus (combo_box->priv->popup_window);
761   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
762                                 TRUE);
763
764   if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view))
765     {
766       gdk_keyboard_grab (combo_box->priv->popup_window->window,
767                          FALSE, GDK_CURRENT_TIME);
768       gtk_widget_grab_focus (combo_box->priv->tree_view);
769     }
770 }
771
772 static void
773 gtk_combo_box_popdown (GtkComboBox *combo_box)
774 {
775   if (GTK_IS_MENU (combo_box->priv->popup_widget))
776     {
777       gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget));
778       return;
779     }
780
781   gtk_widget_hide_all (combo_box->priv->popup_window);
782   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
783                                 FALSE);
784 }
785
786 static gint
787 gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
788                                     GtkTreePath *path)
789 {
790   gint padding;
791   GtkRequisition req;
792
793   if (combo_box->priv->cell_view)
794     gtk_widget_style_get (combo_box->priv->cell_view,
795                           "focus-line-width", &padding,
796                           NULL);
797   else
798     padding = 0;
799
800   /* add some pixels for good measure */
801   padding += BONUS_PADDING;
802
803   if (combo_box->priv->cell_view)
804     gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
805                                    path, &req);
806   else
807     req.width = 0;
808
809   return req.width + padding;
810 }
811
812 static void
813 gtk_combo_box_remeasure (GtkComboBox *combo_box)
814 {
815   GtkTreeIter iter;
816   GtkTreePath *path;
817   gint padding = 0;
818
819   if (!gtk_tree_model_get_iter_first (combo_box->priv->model, &iter))
820     return;
821
822   combo_box->priv->width = 0;
823
824   path = gtk_tree_path_new_from_indices (0, -1);
825
826   if (combo_box->priv->cell_view)
827     gtk_widget_style_get (combo_box->priv->cell_view,
828                           "focus-line-width", &padding,
829                           NULL);
830   else
831     padding = 0;
832
833   /* add some pixels for good measure */
834   padding += BONUS_PADDING;
835
836   do
837     {
838       GtkRequisition req;
839
840       if (combo_box->priv->cell_view)
841         gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
842                                        path, &req);
843       else
844         req.width = 0;
845
846       combo_box->priv->width = MAX (combo_box->priv->width,
847                                     req.width + padding);
848
849       gtk_tree_path_next (path);
850     }
851   while (gtk_tree_model_iter_next (combo_box->priv->model, &iter));
852
853   gtk_tree_path_free (path);
854 }
855
856 static void
857 gtk_combo_box_size_request (GtkWidget      *widget,
858                             GtkRequisition *requisition)
859 {
860   gint width, height;
861   GtkRequisition bin_req;
862
863   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
864
865   /* common */
866   gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
867   gtk_combo_box_remeasure (combo_box);
868   bin_req.width = MAX (bin_req.width, combo_box->priv->width);
869
870   if (!combo_box->priv->tree_view)
871     {
872       /* menu mode */
873
874       if (combo_box->priv->cell_view)
875         {
876           GtkRequisition sep_req, arrow_req;
877           gint border_width, xthickness, ythickness;
878
879           border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
880           xthickness = combo_box->priv->button->style->xthickness;
881           ythickness = combo_box->priv->button->style->ythickness;
882
883           bin_req.width = MAX (bin_req.width, combo_box->priv->width);
884
885           gtk_widget_size_request (combo_box->priv->separator, &sep_req);
886           gtk_widget_size_request (combo_box->priv->arrow, &arrow_req);
887
888           height = MAX (sep_req.height, arrow_req.height);
889           height = MAX (height, bin_req.height);
890
891           width = bin_req.width + sep_req.width + arrow_req.width;
892
893           height += border_width + 1 + xthickness * 2 + 4;
894           width += border_width + 1 + ythickness * 2 + 4;
895
896           requisition->width = width;
897           requisition->height = height;
898         }
899       else
900         {
901           GtkRequisition but_req;
902
903           gtk_widget_size_request (combo_box->priv->button, &but_req);
904
905           requisition->width = bin_req.width + but_req.width;
906           requisition->height = MAX (bin_req.height, but_req.height);
907         }
908     }
909   else
910     {
911       /* list mode */
912       GtkRequisition button_req;
913
914       /* sample + frame */
915       *requisition = bin_req;
916
917       if (combo_box->priv->cell_view_frame)
918         {
919           requisition->width += 2 *
920             (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
921              GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
922           requisition->height += 2 *
923             (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
924              GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
925         }
926
927       /* the button */
928       gtk_widget_size_request (combo_box->priv->button, &button_req);
929
930       requisition->height = MAX (requisition->height, button_req.height);
931       requisition->width += button_req.width;
932     }
933 }
934
935 static void
936 gtk_combo_box_size_allocate (GtkWidget     *widget,
937                              GtkAllocation *allocation)
938 {
939   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
940   GtkAllocation child;
941   GtkRequisition req;
942
943   widget->allocation = *allocation;
944
945   if (!combo_box->priv->tree_view)
946     {
947       if (combo_box->priv->cell_view)
948         {
949           gint border_width, xthickness, ythickness;
950           gint width;
951
952           /* menu mode */
953           gtk_widget_size_allocate (combo_box->priv->button, allocation);
954
955           /* set some things ready */
956           border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
957           xthickness = combo_box->priv->button->style->xthickness;
958           ythickness = combo_box->priv->button->style->ythickness;
959
960           child.x = allocation->x + border_width + 1 + xthickness + 2;
961           child.y = allocation->y + border_width + 1 + ythickness + 2;
962
963           width = allocation->width - (border_width + 1 + ythickness * 2 + 4);
964
965           /* handle the childs */
966           gtk_widget_size_request (combo_box->priv->arrow, &req);
967           child.width = req.width;
968           child.height = allocation->height - 2 * (child.y - allocation->y);
969           child.x += width - req.width;
970           gtk_widget_size_allocate (combo_box->priv->arrow, &child);
971
972           gtk_widget_size_request (combo_box->priv->separator, &req);
973           child.width = req.width;
974           child.x -= req.width;
975           gtk_widget_size_allocate (combo_box->priv->separator, &child);
976
977           child.width = child.x;
978           child.x = allocation->x + border_width + 1 + xthickness + 2;
979           child.width -= child.x;
980
981           gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
982         }
983       else
984         {
985           gtk_widget_size_request (combo_box->priv->button, &req);
986           child.x = allocation->x + allocation->width - req.width;
987           child.y = allocation->y;
988           child.width = req.width;
989           child.height = allocation->height;
990           gtk_widget_size_allocate (combo_box->priv->button, &child);
991
992           child.x = allocation->x;
993           child.y = allocation->y;
994           child.width = allocation->width - req.width;
995           gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
996         }
997     }
998   else
999     {
1000       /* list mode */
1001
1002       /* button */
1003       gtk_widget_size_request (combo_box->priv->button, &req);
1004       child.x = allocation->x + allocation->width - req.width;
1005       child.y = allocation->y;
1006       child.width = req.width;
1007       child.height = allocation->height;
1008       gtk_widget_size_allocate (combo_box->priv->button, &child);
1009
1010       /* frame */
1011       child.x = allocation->x;
1012       child.y = allocation->y;
1013       child.width = allocation->width - req.width;
1014       child.height = allocation->height;
1015
1016       if (combo_box->priv->cell_view_frame)
1017         {
1018           gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child);
1019
1020           /* the sample */
1021           child.x +=
1022             GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1023             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
1024           child.y +=
1025             GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1026             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
1027           child.width -= 2 * (
1028             GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1029             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
1030           child.height -= 2 * (
1031             GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
1032             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
1033         }
1034
1035       gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
1036     }
1037 }
1038
1039 static void
1040 gtk_combo_box_unset_model (GtkComboBox *combo_box)
1041 {
1042   if (!combo_box->priv->tree_view)
1043     {
1044       /* menu mode */
1045       g_signal_handler_disconnect (combo_box->priv->model,
1046                                    combo_box->priv->inserted_id);
1047       g_signal_handler_disconnect (combo_box->priv->model,
1048                                    combo_box->priv->deleted_id);
1049       g_signal_handler_disconnect (combo_box->priv->model,
1050                                    combo_box->priv->changed_id);
1051
1052       combo_box->priv->inserted_id =
1053       combo_box->priv->deleted_id =
1054       combo_box->priv->changed_id = -1;
1055
1056       if (combo_box->priv->popup_widget)
1057         gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget),
1058                                (GtkCallback)gtk_widget_destroy, NULL);
1059     }
1060   else
1061     {
1062       /* list mode */
1063       g_signal_handler_disconnect (combo_box->priv->model,
1064                                    combo_box->priv->changed_id);
1065       combo_box->priv->changed_id = -1;
1066     }
1067 }
1068
1069 static void
1070 gtk_combo_box_set_model_internal (GtkComboBox *combo_box)
1071 {
1072   if (!combo_box->priv->tree_view)
1073     {
1074       /* menu mode */
1075       combo_box->priv->inserted_id =
1076         g_signal_connect (combo_box->priv->model, "row_inserted",
1077                           G_CALLBACK (gtk_combo_box_menu_row_inserted),
1078                           combo_box);
1079       combo_box->priv->deleted_id =
1080         g_signal_connect (combo_box->priv->model, "row_deleted",
1081                           G_CALLBACK (gtk_combo_box_menu_row_deleted),
1082                           combo_box);
1083       combo_box->priv->changed_id =
1084         g_signal_connect (combo_box->priv->model, "row_changed",
1085                           G_CALLBACK (gtk_combo_box_menu_row_changed),
1086                           combo_box);
1087     }
1088   else
1089     {
1090       /* list mode */
1091       gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
1092                                combo_box->priv->model);
1093
1094       combo_box->priv->changed_id =
1095         g_signal_connect (combo_box->priv->model, "row_changed",
1096                           G_CALLBACK (gtk_combo_box_list_row_changed),
1097                           combo_box);
1098     }
1099 }
1100
1101 static void
1102 gtk_combo_box_forall (GtkContainer *container,
1103                       gboolean      include_internals,
1104                       GtkCallback   callback,
1105                       gpointer      callback_data)
1106 {
1107   GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1108
1109   if (include_internals)
1110     {
1111       if (!combo_box->priv->tree_view)
1112         {
1113           if (combo_box->priv->cell_view && combo_box->priv->button)
1114             {
1115               (* callback) (combo_box->priv->button, callback_data);
1116               (* callback) (combo_box->priv->separator, callback_data);
1117               (* callback) (combo_box->priv->arrow, callback_data);
1118             }
1119           else if (combo_box->priv->arrow)
1120             {
1121               (* callback) (combo_box->priv->button, callback_data);
1122               (* callback) (combo_box->priv->arrow, callback_data);
1123             }
1124         }
1125       else
1126         {
1127           (* callback) (combo_box->priv->button, callback_data);
1128           if (combo_box->priv->cell_view_frame)
1129             (* callback) (combo_box->priv->cell_view_frame, callback_data);
1130         }
1131     }
1132
1133   if (GTK_BIN (container)->child)
1134     (* callback) (GTK_BIN (container)->child, callback_data);
1135 }
1136
1137 static gboolean
1138 gtk_combo_box_expose_event (GtkWidget      *widget,
1139                             GdkEventExpose *event)
1140 {
1141   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1142
1143   if (!combo_box->priv->tree_view)
1144     {
1145       gtk_container_propagate_expose (GTK_CONTAINER (widget),
1146                                       combo_box->priv->button, event);
1147
1148       if (combo_box->priv->separator)
1149         {
1150           gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1151                                           combo_box->priv->separator, event);
1152
1153           /* if not in this case, arrow gets its expose event from button */
1154           gtk_container_propagate_expose (GTK_CONTAINER (combo_box->priv->button),
1155                                           combo_box->priv->arrow, event);
1156         }
1157     }
1158   else
1159     {
1160       gtk_container_propagate_expose (GTK_CONTAINER (widget),
1161                                       combo_box->priv->button, event);
1162
1163       if (combo_box->priv->cell_view_frame)
1164         gtk_container_propagate_expose (GTK_CONTAINER (widget),
1165                                         combo_box->priv->cell_view_frame, event);
1166     }
1167
1168   gtk_container_propagate_expose (GTK_CONTAINER (widget),
1169                                   GTK_BIN (widget)->child, event);
1170
1171   return FALSE;
1172 }
1173
1174 static gboolean
1175 gtk_combo_box_scroll_event (GtkWidget          *widget,
1176                             GdkEventScroll     *event)
1177 {
1178   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1179   gint index;
1180   gint items;
1181     
1182   index = gtk_combo_box_get_active (combo_box);
1183
1184   if (index != -1)
1185     {
1186       items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1187       
1188       if (event->direction == GDK_SCROLL_UP)
1189         index--;
1190       else 
1191         index++;
1192
1193       gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
1194     }
1195
1196   return TRUE;
1197 }
1198
1199 /*
1200  * menu style
1201  */
1202
1203 static void
1204 cell_view_sync_cells (GtkComboBox *combo_box,
1205                       GtkCellView *cell_view)
1206 {
1207   GSList *k;
1208
1209   for (k = combo_box->priv->cells; k; k = k->next)
1210     {
1211       GSList *j;
1212       ComboCellInfo *info = (ComboCellInfo *)k->data;
1213
1214       if (info->pack == GTK_PACK_START)
1215         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view),
1216                                     info->cell, info->expand);
1217       else if (info->pack == GTK_PACK_END)
1218         gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view),
1219                                   info->cell, info->expand);
1220
1221       gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view),
1222                                           info->cell,
1223                                           info->func, info->func_data, NULL);
1224
1225       for (j = info->attributes; j; j = j->next->next)
1226         {
1227           gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view),
1228                                          info->cell,
1229                                          j->data,
1230                                          GPOINTER_TO_INT (j->next->data));
1231         }
1232     }
1233 }
1234
1235 static void
1236 gtk_combo_box_menu_setup (GtkComboBox *combo_box,
1237                           gboolean     add_childs)
1238 {
1239   GtkWidget *box;
1240
1241   if (combo_box->priv->cell_view)
1242     {
1243       combo_box->priv->button = gtk_toggle_button_new ();
1244       g_signal_connect (combo_box->priv->button, "toggled",
1245                         G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1246       gtk_widget_set_parent (combo_box->priv->button,
1247                              GTK_BIN (combo_box)->child->parent);
1248
1249       combo_box->priv->separator = gtk_vseparator_new ();
1250       gtk_widget_set_parent (combo_box->priv->separator,
1251                              combo_box->priv->button);
1252       gtk_widget_show (combo_box->priv->separator);
1253
1254       combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1255       gtk_widget_set_parent (combo_box->priv->arrow, combo_box->priv->button);
1256       gtk_widget_show (combo_box->priv->arrow);
1257
1258       gtk_widget_show_all (combo_box->priv->button);
1259
1260       if (GTK_WIDGET_MAPPED (GTK_BIN (combo_box)->child))
1261         {
1262           /* I have no clue why, but we need to manually map in this case. */
1263           gtk_widget_map (combo_box->priv->separator);
1264           gtk_widget_map (combo_box->priv->arrow);
1265         }
1266     }
1267   else
1268     {
1269       combo_box->priv->button = gtk_toggle_button_new ();
1270       g_signal_connect (combo_box->priv->button, "toggled",
1271                         G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1272       gtk_widget_set_parent (combo_box->priv->button,
1273                              GTK_BIN (combo_box)->child->parent);
1274
1275       combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1276       gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1277                          combo_box->priv->arrow);
1278       gtk_widget_show_all (combo_box->priv->button);
1279     }
1280
1281   g_signal_connect (combo_box->priv->button, "button_press_event",
1282                     G_CALLBACK (gtk_combo_box_menu_button_press),
1283                     combo_box);
1284
1285   /* create our funky menu */
1286   box = gtk_menu_new ();
1287   gtk_combo_box_set_popup_widget (combo_box, box);
1288
1289   /* add items */
1290   if (add_childs)
1291     gtk_combo_box_menu_fill (combo_box);
1292 }
1293
1294 static void
1295 gtk_combo_box_menu_fill (GtkComboBox *combo_box)
1296 {
1297   gint i, items;
1298   GtkWidget *menu;
1299   GtkWidget *tmp;
1300
1301   if (!combo_box->priv->model)
1302     return;
1303
1304   items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1305   menu = combo_box->priv->popup_widget;
1306
1307   for (i = 0; i < items; i++)
1308     {
1309       GtkTreePath *path;
1310
1311       path = gtk_tree_path_new_from_indices (i, -1);
1312       tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1313                                                     path);
1314       g_signal_connect (tmp, "activate",
1315                         G_CALLBACK (gtk_combo_box_menu_item_activate),
1316                         combo_box);
1317
1318       cell_view_sync_cells (combo_box,
1319                             GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1320
1321       gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp);
1322       gtk_widget_show (tmp);
1323
1324       gtk_tree_path_free (path);
1325     }
1326 }
1327
1328 static void
1329 gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
1330 {
1331   /* disconnect signal handlers */
1332   gtk_combo_box_unset_model (combo_box);
1333
1334   g_signal_handlers_disconnect_matched (combo_box->priv->button,
1335                                         G_SIGNAL_MATCH_DATA,
1336                                         0, 0, NULL,
1337                                         gtk_combo_box_menu_button_press, NULL);
1338
1339   /* unparent will remove our latest ref */
1340   if (combo_box->priv->cell_view)
1341     {
1342       gtk_widget_unparent (combo_box->priv->arrow);
1343       gtk_widget_unparent (combo_box->priv->separator);
1344       gtk_widget_unparent (combo_box->priv->button);
1345     }
1346   else
1347     {
1348       /* will destroy the arrow too */
1349       gtk_widget_unparent (combo_box->priv->button);
1350     }
1351
1352   /* changing the popup window will unref the menu and the childs */
1353 }
1354
1355 /*
1356  * grid
1357  */
1358
1359 static void
1360 gtk_combo_box_item_get_size (GtkComboBox *combo_box,
1361                              gint         index,
1362                              gint        *cols,
1363                              gint        *rows)
1364 {
1365   GtkTreeIter iter;
1366
1367   gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index);
1368
1369   if (cols)
1370     {
1371       if (combo_box->priv->col_column == -1)
1372         *cols = 1;
1373       else
1374         gtk_tree_model_get (combo_box->priv->model, &iter,
1375                             combo_box->priv->col_column, cols,
1376                             -1);
1377     }
1378
1379   if (rows)
1380     {
1381       if (combo_box->priv->row_column == -1)
1382         *rows = 1;
1383       else
1384         gtk_tree_model_get (combo_box->priv->model, &iter,
1385                             combo_box->priv->row_column, rows,
1386                             -1);
1387     }
1388 }
1389
1390 static gboolean
1391 menu_occupied (GtkMenu *menu,
1392                guint    left_attach,
1393                guint    right_attach,
1394                guint    top_attach,
1395                guint    bottom_attach)
1396 {
1397   GList *i;
1398
1399   g_return_val_if_fail (GTK_IS_MENU (menu), TRUE);
1400   g_return_val_if_fail (left_attach < right_attach, TRUE);
1401   g_return_val_if_fail (top_attach < bottom_attach, TRUE);
1402
1403   for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
1404     {
1405       guint l, r, b, t;
1406       gboolean h_intersect = FALSE;
1407       gboolean v_intersect = FALSE;
1408
1409       gtk_container_child_get (GTK_CONTAINER (menu), i->data,
1410                                "left_attach", &l,
1411                                "right_attach", &r,
1412                                "bottom_attach", &b,
1413                                "top_attach", &t,
1414                                NULL);
1415
1416       /* look if this item intersects with the given coordinates */
1417       h_intersect  = left_attach <= l && l <= right_attach;
1418       h_intersect &= left_attach <= r && r <= right_attach;
1419
1420       v_intersect  = top_attach <= t && t <= bottom_attach;
1421       v_intersect &= top_attach <= b && b <= bottom_attach;
1422
1423       if (h_intersect && v_intersect)
1424         return TRUE;
1425     }
1426
1427   return FALSE;
1428 }
1429
1430 static void
1431 gtk_combo_box_relayout_item (GtkComboBox *combo_box,
1432                              gint         index)
1433 {
1434   gint current_col = 0, current_row = 0;
1435   gint rows, cols;
1436   GList *list;
1437   GtkWidget *item;
1438   GtkWidget *menu;
1439
1440   menu = combo_box->priv->popup_widget;
1441   if (!GTK_IS_MENU_SHELL (menu))
1442     return;
1443
1444   list = gtk_container_get_children (GTK_CONTAINER (menu));
1445   item = g_list_nth_data (list, index);
1446
1447   gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
1448
1449   /* look for a good spot */
1450   while (1)
1451     {
1452       if (current_col + cols > combo_box->priv->wrap_width)
1453         {
1454           current_col = 0;
1455           current_row++;
1456         }
1457
1458       if (!menu_occupied (GTK_MENU (menu),
1459                           current_col, current_col + cols,
1460                           current_row, current_row + rows))
1461         break;
1462
1463       current_col++;
1464     }
1465
1466   /* set attach props */
1467   gtk_menu_attach (GTK_MENU (menu), item,
1468                    current_col, current_col + cols,
1469                    current_row, current_row + rows);
1470 }
1471
1472 static void
1473 gtk_combo_box_relayout (GtkComboBox *combo_box)
1474 {
1475   gint i, items;
1476   GList *list, *j;
1477   GtkWidget *menu;
1478
1479   /* ensure we are in menu style */
1480   if (combo_box->priv->tree_view)
1481     gtk_combo_box_list_destroy (combo_box);
1482
1483   menu = combo_box->priv->popup_widget;
1484
1485   if (!GTK_IS_MENU_SHELL (menu))
1486     {
1487       gtk_combo_box_menu_setup (combo_box, FALSE);
1488       menu = combo_box->priv->popup_widget;
1489     }
1490
1491   /* get rid of all children */
1492   g_return_if_fail (GTK_IS_MENU_SHELL (menu));
1493
1494   list = gtk_container_get_children (GTK_CONTAINER (menu));
1495
1496   for (j = g_list_last (list); j; j = j->prev)
1497     gtk_container_remove (GTK_CONTAINER (menu), j->data);
1498
1499   g_list_free (j);
1500
1501   /* and relayout */
1502   items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
1503
1504   for (i = 0; i < items; i++)
1505     {
1506       GtkWidget *tmp;
1507       GtkTreePath *path;
1508
1509       path = gtk_tree_path_new_from_indices (i, -1);
1510       tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
1511                                                     path);
1512
1513       g_signal_connect (tmp, "activate",
1514                         G_CALLBACK (gtk_combo_box_menu_item_activate),
1515                         combo_box);
1516
1517       cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child));
1518
1519       gtk_menu_shell_insert (GTK_MENU_SHELL (menu), tmp, i);
1520
1521       if (combo_box->priv->wrap_width)
1522         gtk_combo_box_relayout_item (combo_box, i);
1523
1524       gtk_widget_show (tmp);
1525
1526       gtk_tree_path_free (path);
1527     }
1528 }
1529
1530 /* callbacks */
1531 static gboolean
1532 gtk_combo_box_menu_button_press (GtkWidget      *widget,
1533                                  GdkEventButton *event,
1534                                  gpointer        user_data)
1535 {
1536   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1537
1538   if (! GTK_IS_MENU (combo_box->priv->popup_widget))
1539     return FALSE;
1540
1541   if (event->type == GDK_BUTTON_PRESS && event->button == 1)
1542     {
1543       combo_box->priv->popup_in_progress = TRUE;
1544       gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
1545                       NULL, NULL,
1546                       gtk_combo_box_menu_position, combo_box,
1547                       event->button, event->time);
1548
1549       return TRUE;
1550     }
1551
1552   return FALSE;
1553 }
1554
1555 static void
1556 gtk_combo_box_menu_item_activate (GtkWidget *item,
1557                                   gpointer   user_data)
1558 {
1559   gint index;
1560   GtkWidget *menu;
1561   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1562
1563   menu = combo_box->priv->popup_widget;
1564   g_return_if_fail (GTK_IS_MENU (menu));
1565
1566   index = g_list_index (GTK_MENU_SHELL (menu)->children, item);
1567
1568   gtk_combo_box_set_active (combo_box, index);
1569 }
1570
1571 static void
1572 gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
1573                                  GtkTreePath  *path,
1574                                  GtkTreeIter  *iter,
1575                                  gpointer      user_data)
1576 {
1577   GtkWidget *menu;
1578   GtkWidget *item;
1579   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1580
1581   if (!combo_box->priv->popup_widget)
1582     return;
1583
1584   menu = combo_box->priv->popup_widget;
1585   g_return_if_fail (GTK_IS_MENU (menu));
1586
1587   item = gtk_cell_view_menu_item_new_from_model (model, path);
1588   g_signal_connect (item, "activate",
1589                     G_CALLBACK (gtk_combo_box_menu_item_activate),
1590                     combo_box);
1591
1592   cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child));
1593
1594   gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item,
1595                          gtk_tree_path_get_indices (path)[0]);
1596   gtk_widget_show (item);
1597 }
1598
1599 static void
1600 gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
1601                                 GtkTreePath  *path,
1602                                 gpointer      user_data)
1603 {
1604   gint index, items;
1605   GtkWidget *menu;
1606   GtkWidget *item;
1607   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1608
1609   if (!combo_box->priv->popup_widget)
1610     return;
1611
1612   index = gtk_tree_path_get_indices (path)[0];
1613   items = gtk_tree_model_iter_n_children (model, NULL);
1614
1615   if (gtk_combo_box_get_active (combo_box) == index)
1616     gtk_combo_box_set_active (combo_box, index + 1 % items);
1617
1618   menu = combo_box->priv->popup_widget;
1619   g_return_if_fail (GTK_IS_MENU (menu));
1620
1621   item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index);
1622   g_return_if_fail (GTK_IS_MENU_ITEM (item));
1623
1624   gtk_container_remove (GTK_CONTAINER (menu), item);
1625 }
1626
1627 static void
1628 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
1629                                 GtkTreePath  *path,
1630                                 GtkTreeIter  *iter,
1631                                 gpointer      user_data)
1632 {
1633   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1634   gint width;
1635
1636   if (!combo_box->priv->popup_widget)
1637     return;
1638
1639   if (combo_box->priv->wrap_width)
1640     gtk_combo_box_relayout_item (combo_box,
1641                                  gtk_tree_path_get_indices (path)[0]);
1642
1643   width = gtk_combo_box_calc_requested_width (combo_box, path);
1644
1645   if (width > combo_box->priv->width)
1646     {
1647       gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
1648       gtk_widget_queue_resize (combo_box->priv->cell_view);
1649       combo_box->priv->width = width;
1650     }
1651 }
1652
1653 /*
1654  * list style
1655  */
1656
1657 static void
1658 gtk_combo_box_list_setup (GtkComboBox *combo_box)
1659 {
1660   GSList *i;
1661   GtkTreeSelection *sel;
1662
1663   combo_box->priv->button = gtk_toggle_button_new ();
1664   gtk_widget_set_parent (combo_box->priv->button,
1665                          GTK_BIN (combo_box)->child->parent);
1666   g_signal_connect (combo_box->priv->button, "button_press_event",
1667                     G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
1668   g_signal_connect (combo_box->priv->button, "toggled",
1669                     G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
1670
1671   combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1672   gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
1673                      combo_box->priv->arrow);
1674   gtk_widget_show_all (combo_box->priv->button);
1675
1676   if (combo_box->priv->cell_view)
1677     {
1678       combo_box->priv->cell_view_frame = gtk_frame_new (NULL);
1679       gtk_widget_set_parent (combo_box->priv->cell_view_frame,
1680                              GTK_BIN (combo_box)->child->parent);
1681       gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
1682                                  GTK_SHADOW_IN);
1683
1684       g_object_set (G_OBJECT (combo_box->priv->cell_view),
1685                     "background", "white",
1686                     "background_set", TRUE,
1687                     NULL);
1688
1689       gtk_widget_show (combo_box->priv->cell_view_frame);
1690     }
1691
1692   combo_box->priv->tree_view = gtk_tree_view_new ();
1693   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1694   gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1695   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view),
1696                                      FALSE);
1697
1698   g_signal_connect (combo_box->priv->tree_view, "button_press_event",
1699                     G_CALLBACK (gtk_combo_box_list_button_pressed),
1700                     combo_box);
1701   g_signal_connect (combo_box->priv->tree_view, "button_release_event",
1702                     G_CALLBACK (gtk_combo_box_list_button_released),
1703                     combo_box);
1704   g_signal_connect (combo_box->priv->tree_view, "key_press_event",
1705                     G_CALLBACK (gtk_combo_box_list_key_press),
1706                     combo_box);
1707
1708   combo_box->priv->column = gtk_tree_view_column_new ();
1709   gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view),
1710                                combo_box->priv->column);
1711
1712   /* set the models */
1713   gtk_combo_box_set_model_internal (combo_box);
1714
1715   /* sync up */
1716   for (i = combo_box->priv->cells; i; i = i->next)
1717     {
1718       GSList *j;
1719       ComboCellInfo *info = (ComboCellInfo *)i->data;
1720
1721       if (info->pack == GTK_PACK_START)
1722         gtk_tree_view_column_pack_start (combo_box->priv->column,
1723                                          info->cell, info->expand);
1724       else if (info->pack == GTK_PACK_END)
1725         gtk_tree_view_column_pack_end (combo_box->priv->column,
1726                                        info->cell, info->expand);
1727
1728       for (j = info->attributes; j; j = j->next->next)
1729         {
1730           gtk_tree_view_column_add_attribute (combo_box->priv->column,
1731                                               info->cell,
1732                                               j->data,
1733                                               GPOINTER_TO_INT (j->next->data));
1734         }
1735     }
1736
1737   if (combo_box->priv->active_item != -1)
1738     {
1739       GtkTreePath *path;
1740
1741       path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1);
1742       if (path)
1743         {
1744           gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view),
1745                                     path, NULL, FALSE);
1746           gtk_tree_path_free (path);
1747         }
1748     }
1749
1750   /* set sample/popup widgets */
1751   gtk_combo_box_set_popup_widget (GTK_COMBO_BOX (combo_box),
1752                                   combo_box->priv->tree_view);
1753
1754   gtk_widget_show (combo_box->priv->tree_view);
1755 }
1756
1757 static void
1758 gtk_combo_box_list_destroy (GtkComboBox *combo_box)
1759 {
1760   /* disconnect signals */
1761   gtk_combo_box_unset_model (combo_box);
1762
1763   g_signal_handlers_disconnect_matched (combo_box->priv->tree_view,
1764                                         G_SIGNAL_MATCH_DATA,
1765                                         0, 0, NULL, NULL, combo_box);
1766   g_signal_handlers_disconnect_matched (combo_box->priv->button,
1767                                         G_SIGNAL_MATCH_DATA,
1768                                         0, 0, NULL,
1769                                         gtk_combo_box_list_button_pressed,
1770                                         NULL);
1771
1772   /* destroy things (unparent will kill the latest ref from us)
1773    * last unref on button will destroy the arrow
1774    */
1775   gtk_widget_unparent (combo_box->priv->button);
1776
1777   if (combo_box->priv->cell_view)
1778     {
1779       g_object_set (G_OBJECT (combo_box->priv->cell_view),
1780                     "background_set", FALSE,
1781                     NULL);
1782
1783       gtk_widget_unparent (combo_box->priv->cell_view_frame);
1784     }
1785
1786   gtk_widget_destroy (combo_box->priv->tree_view);
1787   combo_box->priv->tree_view = NULL;
1788   combo_box->priv->popup_widget = NULL;
1789 }
1790
1791 /* callbacks */
1792 static void
1793 gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box)
1794 {
1795   if (GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view))
1796     gtk_grab_remove (combo_box->priv->tree_view);
1797
1798   if (GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window))
1799     {
1800       gtk_grab_remove (combo_box->priv->popup_window);
1801       gdk_pointer_ungrab (GDK_CURRENT_TIME);
1802     }
1803 }
1804
1805 static gboolean
1806 gtk_combo_box_list_button_pressed (GtkWidget      *widget,
1807                                    GdkEventButton *event,
1808                                    gpointer        data)
1809 {
1810   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1811
1812   GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1813
1814   if (ewidget == combo_box->priv->tree_view)
1815     return TRUE;
1816
1817   if ((ewidget != combo_box->priv->button) ||
1818       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1819     return FALSE;
1820
1821   gtk_combo_box_popup (combo_box);
1822
1823   gtk_grab_add (combo_box->priv->popup_window);
1824   gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE,
1825                     GDK_BUTTON_PRESS_MASK |
1826                     GDK_BUTTON_RELEASE_MASK |
1827                     GDK_POINTER_MOTION_MASK,
1828                     NULL, NULL, GDK_CURRENT_TIME);
1829
1830   gtk_grab_add (combo_box->priv->tree_view);
1831
1832   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
1833                                 TRUE);
1834
1835   combo_box->priv->popup_in_progress = TRUE;
1836
1837   return TRUE;
1838 }
1839
1840 static gboolean
1841 gtk_combo_box_list_button_released (GtkWidget      *widget,
1842                                     GdkEventButton *event,
1843                                     gpointer        data)
1844 {
1845   gboolean ret;
1846   GtkTreePath *path = NULL;
1847
1848   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1849
1850   gboolean popup_in_progress = FALSE;
1851
1852   GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
1853
1854   if (combo_box->priv->popup_in_progress)
1855     {
1856       popup_in_progress = TRUE;
1857       combo_box->priv->popup_in_progress = FALSE;
1858     }
1859
1860   if (ewidget != combo_box->priv->tree_view)
1861     {
1862       if (ewidget == combo_box->priv->button &&
1863           !popup_in_progress &&
1864           gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
1865         {
1866           gtk_combo_box_list_remove_grabs (combo_box);
1867           gtk_combo_box_popdown (combo_box);
1868           return TRUE;
1869         }
1870
1871       /* released outside treeview */
1872       if (ewidget != combo_box->priv->button)
1873         {
1874           gtk_combo_box_list_remove_grabs (combo_box);
1875           gtk_combo_box_popdown (combo_box);
1876
1877           return TRUE;
1878         }
1879
1880       return FALSE;
1881     }
1882
1883   /* drop grabs */
1884   gtk_combo_box_list_remove_grabs (combo_box);
1885
1886   /* select something cool */
1887   ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
1888                                        event->x, event->y,
1889                                        &path,
1890                                        NULL, NULL, NULL);
1891
1892   if (!ret)
1893     return TRUE; /* clicked outside window? */
1894
1895   gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1896   gtk_combo_box_popdown (combo_box);
1897
1898   gtk_tree_path_free (path);
1899
1900   return TRUE;
1901 }
1902
1903 static gboolean
1904 gtk_combo_box_list_key_press (GtkWidget   *widget,
1905                               GdkEventKey *event,
1906                               gpointer     data)
1907 {
1908   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1909
1910   if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
1911        event->keyval == GDK_space || event->keyval == GDK_KP_Space) ||
1912       event->keyval == GDK_Escape)
1913     {
1914       if (event->keyval != GDK_Escape)
1915         {
1916           gboolean ret;
1917           GtkTreeIter iter;
1918           GtkTreeModel *model = NULL;
1919           GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
1920
1921           ret = gtk_tree_selection_get_selected (sel, &model, &iter);
1922           if (ret)
1923             {
1924               GtkTreePath *path;
1925
1926               path = gtk_tree_model_get_path (model, &iter);
1927               if (path)
1928                 {
1929                   gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
1930                   gtk_tree_path_free (path);
1931                 }
1932             }
1933         }
1934       else
1935         /* reset active item -- this is incredibly lame and ugly */
1936         gtk_combo_box_set_active (combo_box,
1937                                   gtk_combo_box_get_active (combo_box));
1938
1939       gtk_combo_box_list_remove_grabs (combo_box);
1940       gtk_combo_box_popdown (combo_box);
1941
1942       return TRUE;
1943     }
1944
1945   return FALSE;
1946 }
1947
1948 static void
1949 gtk_combo_box_list_row_changed (GtkTreeModel *model,
1950                                 GtkTreePath  *path,
1951                                 GtkTreeIter  *iter,
1952                                 gpointer      data)
1953 {
1954   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1955   gint width;
1956
1957   width = gtk_combo_box_calc_requested_width (combo_box, path);
1958
1959   if (width > combo_box->priv->width)
1960     {
1961       gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
1962       gtk_widget_queue_resize (combo_box->priv->cell_view);
1963       combo_box->priv->width = width;
1964     }
1965 }
1966
1967 /*
1968  * GtkCellLayout implementation
1969  */
1970 static void
1971 gtk_combo_box_cell_layout_pack_start (GtkCellLayout   *layout,
1972                                       GtkCellRenderer *cell,
1973                                       gboolean         expand)
1974 {
1975   ComboCellInfo *info;
1976   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
1977   GtkWidget *menu;
1978
1979   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
1980   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1981
1982   info = g_new0 (ComboCellInfo, 1);
1983   info->cell = cell;
1984   info->expand = expand;
1985   info->pack = GTK_PACK_START;
1986
1987   combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
1988
1989   if (combo_box->priv->cell_view)
1990     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
1991                                 cell, expand);
1992
1993   if (combo_box->priv->column)
1994     gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand);
1995
1996   menu = combo_box->priv->popup_widget;
1997   if (GTK_IS_MENU (menu))
1998     {
1999       GList *i, *list;
2000
2001       list = gtk_container_get_children (GTK_CONTAINER (menu));
2002       for (i = list; i; i = i->next)
2003         {
2004           GtkCellView *view;
2005
2006           if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2007             view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2008           else
2009             view = GTK_CELL_VIEW (i->data);
2010
2011           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand);
2012         }
2013       g_list_free (list);
2014     }
2015 }
2016
2017 static void
2018 gtk_combo_box_cell_layout_pack_end (GtkCellLayout   *layout,
2019                                     GtkCellRenderer *cell,
2020                                     gboolean         expand)
2021 {
2022   ComboCellInfo *info;
2023   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2024   GtkWidget *menu;
2025
2026   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2027   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2028
2029   info = g_new0 (ComboCellInfo, 1);
2030   info->cell = cell;
2031   info->expand = expand;
2032   info->pack = GTK_PACK_END;
2033
2034   if (combo_box->priv->cell_view)
2035     gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2036                               cell, expand);
2037
2038   if (combo_box->priv->column)
2039     gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand);
2040
2041   menu = combo_box->priv->popup_widget;
2042   if (GTK_IS_MENU (menu))
2043     {
2044       GList *i, *list;
2045
2046       list = gtk_container_get_children (GTK_CONTAINER (menu));
2047       for (i = list; i; i = i->next)
2048         {
2049           GtkCellView *view;
2050
2051           if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2052             view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2053           else
2054             view = GTK_CELL_VIEW (i->data);
2055
2056           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand);
2057         }
2058       g_list_free (list);
2059     }
2060 }
2061
2062 static void
2063 gtk_combo_box_cell_layout_clear (GtkCellLayout *layout)
2064 {
2065   GtkWidget *menu;
2066   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2067
2068   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2069
2070   if (combo_box->priv->cell_view)
2071     gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view));
2072
2073   if (combo_box->priv->column)
2074     gtk_tree_view_column_clear (combo_box->priv->column);
2075
2076   menu = combo_box->priv->popup_widget;
2077   if (GTK_IS_MENU (menu))
2078     {
2079       GList *i, *list;
2080
2081       list = gtk_container_get_children (GTK_CONTAINER (menu));
2082       for (i = list; i; i = i->next)
2083         {
2084           GtkCellView *view;
2085
2086           if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2087             view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2088           else
2089             view = GTK_CELL_VIEW (i->data);
2090
2091           gtk_cell_layout_clear (GTK_CELL_LAYOUT (view));
2092         }
2093     }
2094 }
2095
2096 static void
2097 gtk_combo_box_cell_layout_add_attribute (GtkCellLayout   *layout,
2098                                          GtkCellRenderer *cell,
2099                                          const gchar     *attribute,
2100                                          gint             column)
2101 {
2102   ComboCellInfo *info;
2103   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2104   GtkWidget *menu;
2105
2106   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2107   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2108
2109   info = gtk_combo_box_get_cell_info (combo_box, cell);
2110
2111   info->attributes = g_slist_prepend (info->attributes,
2112                                       GINT_TO_POINTER (column));
2113   info->attributes = g_slist_prepend (info->attributes,
2114                                       g_strdup (attribute));
2115
2116   if (combo_box->priv->cell_view)
2117     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
2118                                    cell, attribute, column);
2119
2120   if (combo_box->priv->column)
2121     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column),
2122                                    cell, attribute, column);
2123
2124   menu = combo_box->priv->popup_widget;
2125   if (GTK_IS_MENU (menu))
2126     {
2127       GList *i, *list;
2128
2129       list = gtk_container_get_children (GTK_CONTAINER (menu));
2130       for (i = list; i; i = i->next)
2131         {
2132           GtkCellView *view;
2133
2134           if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2135             view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2136           else
2137             view = GTK_CELL_VIEW (i->data);
2138
2139           gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell,
2140                                          attribute, column);
2141         }
2142       g_list_free (list);
2143     }
2144
2145   gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2146 }
2147
2148 static void
2149 gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
2150                                               GtkCellRenderer       *cell,
2151                                               GtkCellLayoutDataFunc  func,
2152                                               gpointer               func_data,
2153                                               GDestroyNotify         destroy)
2154 {
2155   ComboCellInfo *info;
2156   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2157   GtkWidget *menu;
2158
2159   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2160
2161   info = gtk_combo_box_get_cell_info (combo_box, cell);
2162   g_return_if_fail (info != NULL);
2163
2164   if (info->destroy)
2165     {
2166       GDestroyNotify d = info->destroy;
2167
2168       info->destroy = NULL;
2169       d (info->func_data);
2170     }
2171
2172   info->func = func;
2173   info->func_data = func_data;
2174   info->destroy = destroy;
2175
2176   if (combo_box->priv->cell_view)
2177     gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL);
2178
2179   if (combo_box->priv->column)
2180     gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL);
2181
2182   menu = combo_box->priv->popup_widget;
2183   if (GTK_IS_MENU (menu))
2184     {
2185       GList *i, *list;
2186
2187       list = gtk_container_get_children (GTK_CONTAINER (menu));
2188       for (i = list; i; i = i->next)
2189         {
2190           GtkCellView *view;
2191
2192           if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2193             view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2194           else
2195             view = GTK_CELL_VIEW (i->data);
2196
2197           gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell,
2198                                               func, func_data, NULL);
2199         }
2200       g_list_free (list);
2201     }
2202
2203   gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2204 }
2205
2206 static void
2207 gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout   *layout,
2208                                             GtkCellRenderer *cell)
2209 {
2210   ComboCellInfo *info;
2211   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
2212   GtkWidget *menu;
2213   GSList *list;
2214
2215   g_return_if_fail (GTK_IS_COMBO_BOX (layout));
2216   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2217
2218   info = gtk_combo_box_get_cell_info (combo_box, cell);
2219   g_return_if_fail (info != NULL);
2220
2221   list = info->attributes;
2222   while (list && list->next)
2223     {
2224       g_free (list->data);
2225       list = list->next->next;
2226     }
2227   g_slist_free (list);
2228
2229   info->attributes = NULL;
2230
2231   if (combo_box->priv->cell_view)
2232     gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell);
2233
2234   if (combo_box->priv->column)
2235     gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell);
2236
2237   menu = combo_box->priv->popup_widget;
2238   if (GTK_IS_MENU (menu))
2239     {
2240       GList *i, *list;
2241
2242       list = gtk_container_get_children (GTK_CONTAINER (menu));
2243       for (i = list; i; i = i->next)
2244         {
2245           GtkCellView *view;
2246
2247           if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
2248             view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
2249           else
2250             view = GTK_CELL_VIEW (i->data);
2251
2252           gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell);
2253         }
2254       g_list_free (list);
2255     }
2256
2257   gtk_widget_queue_resize (GTK_WIDGET (combo_box));
2258 }
2259
2260 /*
2261  * public API
2262  */
2263
2264 /**
2265  * gtk_combo_box_new:
2266  *
2267  * Creates a new empty #GtkComboBox.
2268  *
2269  * Return value: A new #GtkComboBox.
2270  *
2271  * Since: 2.4
2272  */
2273 GtkWidget *
2274 gtk_combo_box_new (void)
2275 {
2276   return GTK_WIDGET (g_object_new (gtk_combo_box_get_type (), NULL));
2277 }
2278
2279 /**
2280  * gtk_combo_box_new_with_model:
2281  * @model: A #GtkTreeModel.
2282  *
2283  * Creates a new #GtkComboBox with the model initialized to @model.
2284  *
2285  * Return value: A new #GtkComboBox.
2286  *
2287  * Since: 2.4
2288  */
2289 GtkWidget *
2290 gtk_combo_box_new_with_model (GtkTreeModel *model)
2291 {
2292   GtkComboBox *combo_box;
2293
2294   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
2295
2296   combo_box = GTK_COMBO_BOX (g_object_new (gtk_combo_box_get_type (),
2297                                            "model", model,
2298                                            NULL));
2299
2300   return GTK_WIDGET (combo_box);
2301 }
2302
2303 /**
2304  * gtk_combo_box_set_wrap_width:
2305  * @combo_box: A #GtkComboBox.
2306  * @width: Preferred number of columns.
2307  *
2308  * Sets the wrap width of @combo_box to be @width. The wrap width is basically
2309  * the preferred number of columns when you want to the popup to be layed out
2310  * in a table.
2311  *
2312  * Since: 2.4
2313  */
2314 void
2315 gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
2316                               gint         width)
2317 {
2318   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2319   g_return_if_fail (width > 0);
2320
2321   combo_box->priv->wrap_width = width;
2322
2323   gtk_combo_box_relayout (combo_box);
2324 }
2325
2326 /**
2327  * gtk_combo_box_set_row_span_column:
2328  * @combo_box: A #GtkComboBox.
2329  * @row_span: A column in the model passed during construction.
2330  *
2331  * Sets the column with row span information for @combo_box to be @row_span.
2332  * The row span column contains integers which indicate how many rows
2333  * an item should span.
2334  *
2335  * Since: 2.4
2336  */
2337 void
2338 gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
2339                                    gint         row_span)
2340 {
2341   gint col;
2342
2343   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2344
2345   col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2346   g_return_if_fail (row_span >= 0 && row_span < col);
2347
2348   combo_box->priv->row_column = row_span;
2349
2350   gtk_combo_box_relayout (combo_box);
2351 }
2352
2353 /**
2354  * gtk_combo_box_set_column_span_column:
2355  * @combo_box: A #GtkComboBox.
2356  * @column_span: A column in the model passed during construction.
2357  *
2358  * Sets the column with column span information for @combo_box to be
2359  * @column_span. The column span column contains integers which indicate
2360  * how many columns an item should span.
2361  *
2362  * Since: 2.4
2363  */
2364 void
2365 gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
2366                                       gint         column_span)
2367 {
2368   gint col;
2369
2370   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2371
2372   col = gtk_tree_model_get_n_columns (combo_box->priv->model);
2373   g_return_if_fail (column_span >= 0 && column_span < col);
2374
2375   combo_box->priv->col_column = column_span;
2376
2377   gtk_combo_box_relayout (combo_box);
2378 }
2379
2380 /**
2381  * gtk_combo_box_get_active:
2382  * @combo_box: A #GtkComboBox.
2383  *
2384  * Returns the index of the currently active item, or -1 if there's no
2385  * active item.
2386  *
2387  * Return value: An integer which is the index of the currently active item, or
2388  * -1 if there's no active item.
2389  *
2390  * Since: 2.4
2391  */
2392 gint
2393 gtk_combo_box_get_active (GtkComboBox *combo_box)
2394 {
2395   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
2396
2397   return combo_box->priv->active_item;
2398 }
2399
2400 /**
2401  * gtk_combo_box_set_active:
2402  * @combo_box: A #GtkComboBox.
2403  * @index: An index in the model passed during construction, or -1 to have
2404  * no active item.
2405  *
2406  * Sets the active item of @combo_box to be the item at @index.
2407  *
2408  * Since: 2.4
2409  */
2410 void
2411 gtk_combo_box_set_active (GtkComboBox *combo_box,
2412                           gint         index)
2413 {
2414   GtkTreePath *path;
2415
2416   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2417   /* -1 means "no item selected" */
2418   g_return_if_fail (index >= -1);
2419
2420   if (combo_box->priv->active_item == index)
2421     return;
2422
2423   combo_box->priv->active_item = index;
2424
2425   if (index == -1)
2426     {
2427       if (combo_box->priv->tree_view)
2428         gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)));
2429       else
2430         {
2431           GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2432
2433           if (GTK_IS_MENU (menu))
2434             gtk_menu_set_active (menu, -1);
2435         }
2436
2437       if (combo_box->priv->cell_view)
2438         gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
2439     }
2440   else
2441     {
2442       path = gtk_tree_path_new_from_indices (index, -1);
2443
2444       if (combo_box->priv->tree_view)
2445         gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE);
2446       else
2447         {
2448           GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
2449
2450           if (GTK_IS_MENU (menu))
2451             gtk_menu_set_active (GTK_MENU (menu), index);
2452         }
2453
2454       if (combo_box->priv->cell_view)
2455         gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path);
2456
2457       gtk_tree_path_free (path);
2458     }
2459
2460   g_signal_emit_by_name (combo_box, "changed", NULL, NULL);
2461 }
2462
2463
2464 /**
2465  * gtk_combo_box_get_active_iter:
2466  * @combo_box: A #GtkComboBox
2467  * @iter: The uninitialized #GtkTreeIter.
2468  * 
2469  * Set @iter to point to the current active item, if it exists.
2470  * 
2471  * Return value: %TRUE, if @iter was set
2472  *
2473  * Since: 2.4
2474  **/
2475 gboolean
2476 gtk_combo_box_get_active_iter (GtkComboBox     *combo_box,
2477                                GtkTreeIter     *iter)
2478 {
2479   GtkTreePath *path;
2480   gint active;
2481   gboolean retval;
2482
2483   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
2484
2485   active = gtk_combo_box_get_active (combo_box);
2486   if (active < 0)
2487     return FALSE;
2488
2489   path = gtk_tree_path_new_from_indices (active, -1);
2490   retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box),
2491                                     iter, path);
2492   gtk_tree_path_free (path);
2493
2494   return retval;
2495 }
2496
2497 /**
2498  * gtk_combo_box_set_active_iter:
2499  * @combo_box: A #GtkComboBox
2500  * @iter: The #GtkTreeIter.
2501  * 
2502  * Sets the current active item to be the one referenced by @iter.
2503  * 
2504  * Since: 2.4
2505  **/
2506 void
2507 gtk_combo_box_set_active_iter (GtkComboBox     *combo_box,
2508                                GtkTreeIter     *iter)
2509 {
2510   GtkTreePath *path;
2511
2512   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2513
2514   path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
2515   g_return_if_fail (path != NULL);
2516   g_return_if_fail (gtk_tree_path_get_depth (path) != 1);
2517   
2518   gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
2519   gtk_tree_path_free (path);
2520 }
2521
2522 /**
2523  * gtk_combo_box_set_model:
2524  * @combo_box: A #GtkComboBox.
2525  * @model: A #GtkTreeModel.
2526  *
2527  * Sets the model used by @combo_box to be @model. Will unset a
2528  * previously set model (if applicable).
2529  *
2530  * Since: 2.4
2531  */
2532 void
2533 gtk_combo_box_set_model (GtkComboBox  *combo_box,
2534                          GtkTreeModel *model)
2535 {
2536   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2537   g_return_if_fail (GTK_IS_TREE_MODEL (model));
2538
2539   if (combo_box->priv->model)
2540     {
2541       gtk_combo_box_unset_model (combo_box);
2542       g_object_unref (G_OBJECT (combo_box->priv->model));
2543     }
2544
2545   combo_box->priv->model = model;
2546   g_object_ref (G_OBJECT (combo_box->priv->model));
2547
2548   gtk_combo_box_set_model_internal (combo_box);
2549   if (!combo_box->priv->tree_view && combo_box->priv->popup_widget)
2550     gtk_combo_box_menu_fill (combo_box);
2551
2552   if (combo_box->priv->cell_view)
2553     gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
2554                              combo_box->priv->model);
2555 }
2556
2557 /**
2558  * gtk_combo_box_get_model
2559  * @combo_box: A #GtkComboBox.
2560  *
2561  * Returns the #GtkTreeModel which is acting as data source for @combo_box.
2562  *
2563  * Return value: A #GtkTreeModel which was passed during construction.
2564  *
2565  * Since: 2.4
2566  */
2567 GtkTreeModel *
2568 gtk_combo_box_get_model (GtkComboBox *combo_box)
2569 {
2570   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
2571
2572   return combo_box->priv->model;
2573 }
2574
2575
2576 /* convenience API for simple text combos */
2577
2578 /**
2579  * gtk_combo_box_new_text:
2580  *
2581  * Convenience function which constructs a new text combo box, which is a
2582  * #GtkComboBox just displaying strings. If you use this function to create
2583  * a text combo box, you only want to manipulate it's data source with the
2584  * following convenience functions: gtk_combo_box_append_text(),
2585  * gtk_combo_box_insert_text() and gtk_combo_box_prepend_text().
2586  *
2587  * Return value: A new text combo box.
2588  *
2589  * Since: 2.4
2590  */
2591 GtkWidget *
2592 gtk_combo_box_new_text (void)
2593 {
2594   GtkWidget *combo_box;
2595   GtkCellRenderer *cell;
2596   GtkListStore *store;
2597
2598   store = gtk_list_store_new (1, G_TYPE_STRING);
2599
2600   combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
2601
2602   cell = gtk_cell_renderer_text_new ();
2603   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
2604   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
2605                                   "text", 0,
2606                                   NULL);
2607
2608   return combo_box;
2609 }
2610
2611 /**
2612  * gtk_combo_box_append_text:
2613  * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2614  * @text: A string.
2615  *
2616  * Appends @string to the list of strings stored in @combo_box. Note that
2617  * you can only use this function with combo boxes constructed with
2618  * gtk_combo_box_new_text().
2619  *
2620  * Since: 2.4
2621  */
2622 void
2623 gtk_combo_box_append_text (GtkComboBox *combo_box,
2624                            const gchar *text)
2625 {
2626   GtkTreeIter iter;
2627   GtkListStore *store;
2628
2629   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2630   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2631   g_return_if_fail (text != NULL);
2632
2633   store = GTK_LIST_STORE (combo_box->priv->model);
2634
2635   gtk_list_store_append (store, &iter);
2636   gtk_list_store_set (store, &iter, 0, text, -1);
2637 }
2638
2639 /**
2640  * gtk_combo_box_insert_text:
2641  * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
2642  * @position: An index to insert @text.
2643  * @text: A string.
2644  *
2645  * Inserts @string at @position in the list of strings stored in @combo_box.
2646  * Note that you can only use this function with combo boxes constructed
2647  * with gtk_combo_box_new_text().
2648  *
2649  * Since: 2.4
2650  */
2651 void
2652 gtk_combo_box_insert_text (GtkComboBox *combo_box,
2653                            gint         position,
2654                            const gchar *text)
2655 {
2656   GtkTreeIter iter;
2657   GtkListStore *store;
2658
2659   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2660   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2661   g_return_if_fail (position >= 0);
2662   g_return_if_fail (text != NULL);
2663
2664   store = GTK_LIST_STORE (combo_box->priv->model);
2665
2666   gtk_list_store_insert (store, &iter, position);
2667   gtk_list_store_set (store, &iter, 0, text, -1);
2668 }
2669
2670 /**
2671  * gtk_combo_box_prepend_text:
2672  * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2673  * @text: A string.
2674  *
2675  * Prepends @string to the list of strings stored in @combo_box. Note that
2676  * you can only use this function with combo boxes constructed with
2677  * gtk_combo_box_new_text().
2678  *
2679  * Since: 2.4
2680  */
2681 void
2682 gtk_combo_box_prepend_text (GtkComboBox *combo_box,
2683                             const gchar *text)
2684 {
2685   GtkTreeIter iter;
2686   GtkListStore *store;
2687
2688   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2689   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2690   g_return_if_fail (text != NULL);
2691
2692   store = GTK_LIST_STORE (combo_box->priv->model);
2693
2694   gtk_list_store_prepend (store, &iter);
2695   gtk_list_store_set (store, &iter, 0, text, -1);
2696 }
2697
2698 /**
2699  * gtk_combo_box_remove_text:
2700  * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
2701  * @position: Index of the item to remove.
2702  *
2703  * Removes the string at @position from @combo_box. Note that you can only use
2704  * this function with combo boxes constructed with gtk_combo_box_new_text().
2705  *
2706  * Since: 2.4
2707  */
2708 void
2709 gtk_combo_box_remove_text (GtkComboBox *combo_box,
2710                            gint         position)
2711 {
2712   GtkTreeIter iter;
2713   GtkListStore *store;
2714
2715   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2716   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
2717   g_return_if_fail (position >= 0);
2718
2719   store = GTK_LIST_STORE (combo_box->priv->model);
2720
2721   if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter,
2722                                      NULL, position))
2723     gtk_list_store_remove (store, &iter);
2724 }