]> Pileus Git - ~andy/gtk/blob - gtk/gtkcombobox.c
gtk/: fully remove gtkalias hacks
[~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 "config.h"
21 #include "gtkcombobox.h"
22
23 #include "gtkarrow.h"
24 #include "gtkbindings.h"
25 #include "gtkcelllayout.h"
26 #include "gtkcellrenderertext.h"
27 #include "gtkcellview.h"
28 #include "gtkeventbox.h"
29 #include "gtkframe.h"
30 #include "gtkhbox.h"
31 #include "gtkliststore.h"
32 #include "gtkmain.h"
33 #include "gtkmenu.h"
34 #include "gtkscrolledwindow.h"
35 #include "gtkseparatormenuitem.h"
36 #include "gtktearoffmenuitem.h"
37 #include "gtktogglebutton.h"
38 #include "gtktreeselection.h"
39 #include "gtkvseparator.h"
40 #include "gtkwindow.h"
41 #include "gtkprivate.h"
42
43 #include <gdk/gdkkeysyms.h>
44
45 #include <gobject/gvaluecollector.h>
46
47 #include <string.h>
48 #include <stdarg.h>
49
50 #include "gtkmarshalers.h"
51 #include "gtkintl.h"
52
53 #include "gtktreeprivate.h"
54
55 /* WELCOME, to THE house of evil code */
56
57 typedef struct _ComboCellInfo ComboCellInfo;
58 struct _ComboCellInfo
59 {
60   GtkCellRenderer *cell;
61   GSList *attributes;
62
63   GtkCellLayoutDataFunc func;
64   gpointer func_data;
65   GDestroyNotify destroy;
66
67   guint expand : 1;
68   guint pack : 1;
69 };
70
71 #define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate))
72
73 struct _GtkComboBoxPrivate
74 {
75   GtkTreeModel *model;
76
77   gint col_column;
78   gint row_column;
79
80   gint wrap_width;
81   GtkShadowType shadow_type;
82
83   gint active; /* Only temporary */
84   GtkTreeRowReference *active_row;
85
86   GtkWidget *tree_view;
87   GtkTreeViewColumn *column;
88
89   GtkWidget *cell_view;
90   GtkWidget *cell_view_frame;
91
92   GtkWidget *button;
93   GtkWidget *box;
94   GtkWidget *arrow;
95   GtkWidget *separator;
96
97   GtkWidget *popup_widget;
98   GtkWidget *popup_window;
99   GtkWidget *scrolled_window;
100
101   guint inserted_id;
102   guint deleted_id;
103   guint reordered_id;
104   guint changed_id;
105   guint popup_idle_id;
106   guint activate_button;
107   guint32 activate_time;
108   guint scroll_timer;
109   guint resize_idle_id;
110
111   gint width;
112   gint height;
113   GSList *cells;
114
115   guint popup_in_progress : 1;
116   guint popup_shown : 1;
117   guint add_tearoffs : 1;
118   guint has_frame : 1;
119   guint is_cell_renderer : 1;
120   guint editing_canceled : 1;
121   guint auto_scroll : 1;
122   guint focus_on_click : 1;
123   guint button_sensitivity : 2;
124
125   GtkTreeViewRowSeparatorFunc row_separator_func;
126   gpointer                    row_separator_data;
127   GDestroyNotify              row_separator_destroy;
128
129   GdkDevice *grab_pointer;
130   GdkDevice *grab_keyboard;
131
132   gchar *tearoff_title;
133 };
134
135 /* While debugging this evil code, I have learned that
136  * there are actually 4 modes to this widget, which can
137  * be characterized as follows
138  * 
139  * 1) menu mode, no child added
140  *
141  * tree_view -> NULL
142  * cell_view -> GtkCellView, regular child
143  * cell_view_frame -> NULL
144  * button -> GtkToggleButton set_parent to combo
145  * arrow -> GtkArrow set_parent to button
146  * separator -> GtkVSepator set_parent to button
147  * popup_widget -> GtkMenu
148  * popup_window -> NULL
149  * scrolled_window -> NULL
150  *
151  * 2) menu mode, child added
152  * 
153  * tree_view -> NULL
154  * cell_view -> NULL 
155  * cell_view_frame -> NULL
156  * button -> GtkToggleButton set_parent to combo
157  * arrow -> GtkArrow, child of button
158  * separator -> NULL
159  * popup_widget -> GtkMenu
160  * popup_window -> NULL
161  * scrolled_window -> NULL
162  *
163  * 3) list mode, no child added
164  * 
165  * tree_view -> GtkTreeView, child of scrolled_window
166  * cell_view -> GtkCellView, regular child
167  * cell_view_frame -> GtkFrame, set parent to combo
168  * button -> GtkToggleButton, set_parent to combo
169  * arrow -> GtkArrow, child of button
170  * separator -> NULL
171  * popup_widget -> tree_view
172  * popup_window -> GtkWindow
173  * scrolled_window -> GtkScrolledWindow, child of popup_window
174  *
175  * 4) list mode, child added
176  *
177  * tree_view -> GtkTreeView, child of scrolled_window
178  * cell_view -> NULL
179  * cell_view_frame -> NULL
180  * button -> GtkToggleButton, set_parent to combo
181  * arrow -> GtkArrow, child of button
182  * separator -> NULL
183  * popup_widget -> tree_view
184  * popup_window -> GtkWindow
185  * scrolled_window -> GtkScrolledWindow, child of popup_window
186  * 
187  */
188
189 enum {
190   CHANGED,
191   MOVE_ACTIVE,
192   POPUP,
193   POPDOWN,
194   LAST_SIGNAL
195 };
196
197 enum {
198   PROP_0,
199   PROP_MODEL,
200   PROP_WRAP_WIDTH,
201   PROP_ROW_SPAN_COLUMN,
202   PROP_COLUMN_SPAN_COLUMN,
203   PROP_ACTIVE,
204   PROP_ADD_TEAROFFS,
205   PROP_TEAROFF_TITLE,
206   PROP_HAS_FRAME,
207   PROP_FOCUS_ON_CLICK,
208   PROP_POPUP_SHOWN,
209   PROP_BUTTON_SENSITIVITY,
210   PROP_EDITING_CANCELED
211 };
212
213 static guint combo_box_signals[LAST_SIGNAL] = {0,};
214
215 #define BONUS_PADDING 4
216 #define SCROLL_TIME  100
217
218 /* common */
219
220 static void     gtk_combo_box_cell_layout_init     (GtkCellLayoutIface *iface);
221 static void     gtk_combo_box_cell_editable_init   (GtkCellEditableIface *iface);
222 static void     gtk_combo_box_dispose              (GObject          *object);
223 static void     gtk_combo_box_finalize             (GObject          *object);
224 static void     gtk_combo_box_destroy              (GtkObject        *object);
225
226 static void     gtk_combo_box_set_property         (GObject         *object,
227                                                     guint            prop_id,
228                                                     const GValue    *value,
229                                                     GParamSpec      *spec);
230 static void     gtk_combo_box_get_property         (GObject         *object,
231                                                     guint            prop_id,
232                                                     GValue          *value,
233                                                     GParamSpec      *spec);
234
235 static void     gtk_combo_box_state_changed        (GtkWidget        *widget,
236                                                     GtkStateType      previous);
237 static void     gtk_combo_box_grab_focus           (GtkWidget       *widget);
238 static void     gtk_combo_box_style_set            (GtkWidget       *widget,
239                                                     GtkStyle        *previous);
240 static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
241                                                     gpointer         data);
242 static void     gtk_combo_box_button_state_changed (GtkWidget       *widget,
243                                                     GtkStateType     previous,
244                                                     gpointer         data);
245 static void     gtk_combo_box_add                  (GtkContainer    *container,
246                                                     GtkWidget       *widget);
247 static void     gtk_combo_box_remove               (GtkContainer    *container,
248                                                     GtkWidget       *widget);
249
250 static ComboCellInfo *gtk_combo_box_get_cell_info  (GtkComboBox      *combo_box,
251                                                     GtkCellRenderer  *cell);
252
253 static void     gtk_combo_box_menu_show            (GtkWidget        *menu,
254                                                     gpointer          user_data);
255 static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
256                                                     gpointer          user_data);
257
258 static void     gtk_combo_box_set_popup_widget     (GtkComboBox      *combo_box,
259                                                     GtkWidget        *popup);
260 static void     gtk_combo_box_menu_position_below  (GtkMenu          *menu,
261                                                     gint             *x,
262                                                     gint             *y,
263                                                     gint             *push_in,
264                                                     gpointer          user_data);
265 static void     gtk_combo_box_menu_position_over   (GtkMenu          *menu,
266                                                     gint             *x,
267                                                     gint             *y,
268                                                     gint             *push_in,
269                                                     gpointer          user_data);
270 static void     gtk_combo_box_menu_position        (GtkMenu          *menu,
271                                                     gint             *x,
272                                                     gint             *y,
273                                                     gint             *push_in,
274                                                     gpointer          user_data);
275
276 static gint     gtk_combo_box_calc_requested_width (GtkComboBox      *combo_box,
277                                                     GtkTreePath      *path);
278 static void     gtk_combo_box_remeasure            (GtkComboBox      *combo_box);
279
280 static void     gtk_combo_box_unset_model          (GtkComboBox      *combo_box);
281
282 static void     gtk_combo_box_size_request         (GtkWidget        *widget,
283                                                     GtkRequisition   *requisition);
284 static void     gtk_combo_box_size_allocate        (GtkWidget        *widget,
285                                                     GtkAllocation    *allocation);
286 static void     gtk_combo_box_forall               (GtkContainer     *container,
287                                                     gboolean          include_internals,
288                                                     GtkCallback       callback,
289                                                     gpointer          callback_data);
290 static gboolean gtk_combo_box_expose_event         (GtkWidget        *widget,
291                                                     GdkEventExpose   *event);
292 static gboolean gtk_combo_box_scroll_event         (GtkWidget        *widget,
293                                                     GdkEventScroll   *event);
294 static void     gtk_combo_box_set_active_internal  (GtkComboBox      *combo_box,
295                                                     GtkTreePath      *path);
296
297 static void     gtk_combo_box_check_appearance     (GtkComboBox      *combo_box);
298 static gchar *  gtk_combo_box_real_get_active_text (GtkComboBox      *combo_box);
299 static void     gtk_combo_box_real_move_active     (GtkComboBox      *combo_box,
300                                                     GtkScrollType     scroll);
301 static void     gtk_combo_box_real_popup           (GtkComboBox      *combo_box);
302 static gboolean gtk_combo_box_real_popdown         (GtkComboBox      *combo_box);
303
304 /* listening to the model */
305 static void     gtk_combo_box_model_row_inserted   (GtkTreeModel     *model,
306                                                     GtkTreePath      *path,
307                                                     GtkTreeIter      *iter,
308                                                     gpointer          user_data);
309 static void     gtk_combo_box_model_row_deleted    (GtkTreeModel     *model,
310                                                     GtkTreePath      *path,
311                                                     gpointer          user_data);
312 static void     gtk_combo_box_model_rows_reordered (GtkTreeModel     *model,
313                                                     GtkTreePath      *path,
314                                                     GtkTreeIter      *iter,
315                                                     gint             *new_order,
316                                                     gpointer          user_data);
317 static void     gtk_combo_box_model_row_changed    (GtkTreeModel     *model,
318                                                     GtkTreePath      *path,
319                                                     GtkTreeIter      *iter,
320                                                     gpointer          data);
321 static void     gtk_combo_box_model_row_expanded   (GtkTreeModel     *model,
322                                                     GtkTreePath      *path,
323                                                     GtkTreeIter      *iter,
324                                                     gpointer          data);
325
326 /* list */
327 static void     gtk_combo_box_list_position        (GtkComboBox      *combo_box, 
328                                                     gint             *x, 
329                                                     gint             *y, 
330                                                     gint             *width,
331                                                     gint             *height);
332 static void     gtk_combo_box_list_setup           (GtkComboBox      *combo_box);
333 static void     gtk_combo_box_list_destroy         (GtkComboBox      *combo_box);
334
335 static gboolean gtk_combo_box_list_button_released (GtkWidget        *widget,
336                                                     GdkEventButton   *event,
337                                                     gpointer          data);
338 static gboolean gtk_combo_box_list_key_press       (GtkWidget        *widget,
339                                                     GdkEventKey      *event,
340                                                     gpointer          data);
341 static gboolean gtk_combo_box_list_enter_notify    (GtkWidget        *widget,
342                                                     GdkEventCrossing *event,
343                                                     gpointer          data);
344 static void     gtk_combo_box_list_auto_scroll     (GtkComboBox   *combo,
345                                                     gint           x,
346                                                     gint           y);
347 static gboolean gtk_combo_box_list_scroll_timeout  (GtkComboBox   *combo);
348 static gboolean gtk_combo_box_list_button_pressed  (GtkWidget        *widget,
349                                                     GdkEventButton   *event,
350                                                     gpointer          data);
351
352 static gboolean gtk_combo_box_list_select_func     (GtkTreeSelection *selection,
353                                                     GtkTreeModel     *model,
354                                                     GtkTreePath      *path,
355                                                     gboolean          path_currently_selected,
356                                                     gpointer          data);
357
358 static void     gtk_combo_box_list_row_changed     (GtkTreeModel     *model,
359                                                     GtkTreePath      *path,
360                                                     GtkTreeIter      *iter,
361                                                     gpointer          data);
362 static void     gtk_combo_box_list_popup_resize    (GtkComboBox      *combo_box);
363
364 /* menu */
365 static void     gtk_combo_box_menu_setup           (GtkComboBox      *combo_box,
366                                                     gboolean          add_children);
367 static void     gtk_combo_box_menu_fill            (GtkComboBox      *combo_box);
368 static void     gtk_combo_box_menu_fill_level      (GtkComboBox      *combo_box,
369                                                     GtkWidget        *menu,
370                                                     GtkTreeIter      *iter);
371 static void     gtk_combo_box_update_title         (GtkComboBox      *combo_box);
372 static void     gtk_combo_box_menu_destroy         (GtkComboBox      *combo_box);
373
374 static void     gtk_combo_box_relayout_item        (GtkComboBox      *combo_box,
375                                                     GtkWidget        *item,
376                                                     GtkTreeIter      *iter,
377                                                     GtkWidget        *last);
378 static void     gtk_combo_box_relayout             (GtkComboBox      *combo_box);
379
380 static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
381                                                     GdkEventButton   *event,
382                                                     gpointer          user_data);
383 static void     gtk_combo_box_menu_item_activate   (GtkWidget        *item,
384                                                     gpointer          user_data);
385
386 static void     gtk_combo_box_update_sensitivity   (GtkComboBox      *combo_box);
387 static void     gtk_combo_box_menu_row_inserted    (GtkTreeModel     *model,
388                                                     GtkTreePath      *path,
389                                                     GtkTreeIter      *iter,
390                                                     gpointer          user_data);
391 static void     gtk_combo_box_menu_row_deleted     (GtkTreeModel     *model,
392                                                     GtkTreePath      *path,
393                                                     gpointer          user_data);
394 static void     gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
395                                                     GtkTreePath      *path,
396                                                     GtkTreeIter      *iter,
397                                                     gint             *new_order,
398                                                     gpointer          user_data);
399 static void     gtk_combo_box_menu_row_changed     (GtkTreeModel     *model,
400                                                     GtkTreePath      *path,
401                                                     GtkTreeIter      *iter,
402                                                     gpointer          data);
403 static gboolean gtk_combo_box_menu_key_press       (GtkWidget        *widget,
404                                                     GdkEventKey      *event,
405                                                     gpointer          data);
406 static void     gtk_combo_box_menu_popup           (GtkComboBox      *combo_box,
407                                                     guint             button, 
408                                                     guint32           activate_time);
409 static GtkWidget *gtk_cell_view_menu_item_new      (GtkComboBox      *combo_box,
410                                                     GtkTreeModel     *model,
411                                                     GtkTreeIter      *iter);
412
413 /* cell layout */
414 static void     gtk_combo_box_cell_layout_pack_start         (GtkCellLayout         *layout,
415                                                               GtkCellRenderer       *cell,
416                                                               gboolean               expand);
417 static void     gtk_combo_box_cell_layout_pack_end           (GtkCellLayout         *layout,
418                                                               GtkCellRenderer       *cell,
419                                                               gboolean               expand);
420 static GList   *gtk_combo_box_cell_layout_get_cells          (GtkCellLayout         *layout);
421 static void     gtk_combo_box_cell_layout_clear              (GtkCellLayout         *layout);
422 static void     gtk_combo_box_cell_layout_add_attribute      (GtkCellLayout         *layout,
423                                                               GtkCellRenderer       *cell,
424                                                               const gchar           *attribute,
425                                                               gint                   column);
426 static void     gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
427                                                               GtkCellRenderer       *cell,
428                                                               GtkCellLayoutDataFunc  func,
429                                                               gpointer               func_data,
430                                                               GDestroyNotify         destroy);
431 static void     gtk_combo_box_cell_layout_clear_attributes   (GtkCellLayout         *layout,
432                                                               GtkCellRenderer       *cell);
433 static void     gtk_combo_box_cell_layout_reorder            (GtkCellLayout         *layout,
434                                                               GtkCellRenderer       *cell,
435                                                               gint                   position);
436 static gboolean gtk_combo_box_mnemonic_activate              (GtkWidget    *widget,
437                                                               gboolean      group_cycling);
438
439 static void     gtk_combo_box_sync_cells                     (GtkComboBox   *combo_box,
440                                                               GtkCellLayout *cell_layout);
441 static void     combo_cell_data_func                         (GtkCellLayout   *cell_layout,
442                                                               GtkCellRenderer *cell,
443                                                               GtkTreeModel    *tree_model,
444                                                               GtkTreeIter     *iter,
445                                                               gpointer         data);
446 static void     gtk_combo_box_child_show                     (GtkWidget       *widget,
447                                                               GtkComboBox     *combo_box);
448 static void     gtk_combo_box_child_hide                     (GtkWidget       *widget,
449                                                               GtkComboBox     *combo_box);
450
451 /* GtkBuildable method implementation */
452 static GtkBuildableIface *parent_buildable_iface;
453
454 static void     gtk_combo_box_buildable_init                 (GtkBuildableIface *iface);
455 static gboolean gtk_combo_box_buildable_custom_tag_start     (GtkBuildable  *buildable,
456                                                               GtkBuilder    *builder,
457                                                               GObject       *child,
458                                                               const gchar   *tagname,
459                                                               GMarkupParser *parser,
460                                                               gpointer      *data);
461 static void     gtk_combo_box_buildable_custom_tag_end       (GtkBuildable  *buildable,
462                                                               GtkBuilder    *builder,
463                                                               GObject       *child,
464                                                               const gchar   *tagname,
465                                                               gpointer      *data);
466
467 /* GtkCellEditable method implementations */
468 static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
469                                          GdkEvent        *event);
470
471
472 G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
473                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
474                                                 gtk_combo_box_cell_layout_init)
475                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
476                                                 gtk_combo_box_cell_editable_init)
477                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
478                                                 gtk_combo_box_buildable_init))
479
480
481 /* common */
482 static void
483 gtk_combo_box_class_init (GtkComboBoxClass *klass)
484 {
485   GObjectClass *object_class;
486   GtkObjectClass *gtk_object_class;
487   GtkContainerClass *container_class;
488   GtkWidgetClass *widget_class;
489   GtkBindingSet *binding_set;
490
491   klass->get_active_text = gtk_combo_box_real_get_active_text;
492
493   container_class = (GtkContainerClass *)klass;
494   container_class->forall = gtk_combo_box_forall;
495   container_class->add = gtk_combo_box_add;
496   container_class->remove = gtk_combo_box_remove;
497
498   widget_class = (GtkWidgetClass *)klass;
499   widget_class->size_allocate = gtk_combo_box_size_allocate;
500   widget_class->size_request = gtk_combo_box_size_request;
501   widget_class->expose_event = gtk_combo_box_expose_event;
502   widget_class->scroll_event = gtk_combo_box_scroll_event;
503   widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
504   widget_class->grab_focus = gtk_combo_box_grab_focus;
505   widget_class->style_set = gtk_combo_box_style_set;
506   widget_class->state_changed = gtk_combo_box_state_changed;
507
508   gtk_object_class = (GtkObjectClass *)klass;
509   gtk_object_class->destroy = gtk_combo_box_destroy;
510
511   object_class = (GObjectClass *)klass;
512   object_class->dispose = gtk_combo_box_dispose;
513   object_class->finalize = gtk_combo_box_finalize;
514   object_class->set_property = gtk_combo_box_set_property;
515   object_class->get_property = gtk_combo_box_get_property;
516
517   /* signals */
518   /**
519    * GtkComboBox::changed:
520    * @widget: the object which received the signal
521    * 
522    * The changed signal is emitted when the active
523    * item is changed. The can be due to the user selecting
524    * a different item from the list, or due to a 
525    * call to gtk_combo_box_set_active_iter().
526    * It will also be emitted while typing into a GtkComboBoxEntry, 
527    * as well as when selecting an item from the GtkComboBoxEntry's list.
528    *
529    * Since: 2.4
530    */
531   combo_box_signals[CHANGED] =
532     g_signal_new (I_("changed"),
533                   G_OBJECT_CLASS_TYPE (klass),
534                   G_SIGNAL_RUN_LAST,
535                   G_STRUCT_OFFSET (GtkComboBoxClass, changed),
536                   NULL, NULL,
537                   g_cclosure_marshal_VOID__VOID,
538                   G_TYPE_NONE, 0);
539   /**
540    * GtkComboBox::move-active:
541    * @widget: the object that received the signal
542    * @scroll_type: a #GtkScrollType
543    *
544    * The ::move-active signal is a 
545    * <link linkend="keybinding-signals">keybinding signal</link>
546    * which gets emitted to move the active selection.
547    *
548    * Since: 2.12
549    */
550   combo_box_signals[MOVE_ACTIVE] =
551     g_signal_new_class_handler (I_("move-active"),
552                                 G_OBJECT_CLASS_TYPE (klass),
553                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
554                                 G_CALLBACK (gtk_combo_box_real_move_active),
555                                 NULL, NULL,
556                                 g_cclosure_marshal_VOID__ENUM,
557                                 G_TYPE_NONE, 1,
558                                 GTK_TYPE_SCROLL_TYPE);
559
560   /**
561    * GtkComboBox::popup:
562    * @widget: the object that received the signal
563    *
564    * The ::popup signal is a 
565    * <link linkend="keybinding-signals">keybinding signal</link>
566    * which gets emitted to popup the combo box list.
567    *
568    * The default binding for this signal is Alt+Down.
569    *
570    * Since: 2.12
571    */
572   combo_box_signals[POPUP] =
573     g_signal_new_class_handler (I_("popup"),
574                                 G_OBJECT_CLASS_TYPE (klass),
575                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
576                                 G_CALLBACK (gtk_combo_box_real_popup),
577                                 NULL, NULL,
578                                 g_cclosure_marshal_VOID__VOID,
579                                 G_TYPE_NONE, 0);
580   /**
581    * GtkComboBox::popdown:
582    * @button: the object which received the signal
583    *
584    * The ::popdown signal is a 
585    * <link linkend="keybinding-signals">keybinding signal</link> 
586    * which gets emitted to popdown the combo box list.
587    *
588    * The default bindings for this signal are Alt+Up and Escape.
589    *
590    * Since: 2.12
591    */
592   combo_box_signals[POPDOWN] =
593     g_signal_new_class_handler (I_("popdown"),
594                                 G_OBJECT_CLASS_TYPE (klass),
595                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
596                                 G_CALLBACK (gtk_combo_box_real_popdown),
597                                 NULL, NULL,
598                                 _gtk_marshal_BOOLEAN__VOID,
599                                 G_TYPE_BOOLEAN, 0);
600
601   /* key bindings */
602   binding_set = gtk_binding_set_by_class (widget_class);
603
604   gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_MOD1_MASK,
605                                 "popup", 0);
606   gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, GDK_MOD1_MASK,
607                                 "popup", 0);
608
609   gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_MOD1_MASK,
610                                 "popdown", 0);
611   gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, GDK_MOD1_MASK,
612                                 "popdown", 0);
613   gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
614                                 "popdown", 0);
615
616   gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
617                                 "move-active", 1,
618                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_UP);
619   gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
620                                 "move-active", 1,
621                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_UP);
622   gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
623                                 "move-active", 1,
624                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP);
625   gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
626                                 "move-active", 1,
627                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP);
628   gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
629                                 "move-active", 1,
630                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_START);
631   gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
632                                 "move-active", 1,
633                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_START);
634
635   gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
636                                 "move-active", 1,
637                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_DOWN);
638   gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
639                                 "move-active", 1,
640                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_DOWN);
641   gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
642                                 "move-active", 1,
643                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN);
644   gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
645                                 "move-active", 1,
646                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN);
647   gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
648                                 "move-active", 1,
649                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END);
650   gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
651                                 "move-active", 1,
652                                 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END);
653
654   /* properties */
655   g_object_class_override_property (object_class,
656                                     PROP_EDITING_CANCELED,
657                                     "editing-canceled");
658
659   /**
660    * GtkComboBox:model:
661    *
662    * The model from which the combo box takes the values shown
663    * in the list. 
664    *
665    * Since: 2.4
666    */
667   g_object_class_install_property (object_class,
668                                    PROP_MODEL,
669                                    g_param_spec_object ("model",
670                                                         P_("ComboBox model"),
671                                                         P_("The model for the combo box"),
672                                                         GTK_TYPE_TREE_MODEL,
673                                                         GTK_PARAM_READWRITE));
674
675   /**
676    * GtkComboBox:wrap-width:
677    *
678    * If wrap-width is set to a positive value, the list will be
679    * displayed in multiple columns, the number of columns is
680    * determined by wrap-width.
681    *
682    * Since: 2.4
683    */
684   g_object_class_install_property (object_class,
685                                    PROP_WRAP_WIDTH,
686                                    g_param_spec_int ("wrap-width",
687                                                      P_("Wrap width"),
688                                                      P_("Wrap width for laying out the items in a grid"),
689                                                      0,
690                                                      G_MAXINT,
691                                                      0,
692                                                      GTK_PARAM_READWRITE));
693
694
695   /**
696    * GtkComboBox:row-span-column:
697    *
698    * If this is set to a non-negative value, it must be the index of a column 
699    * of type %G_TYPE_INT in the model. 
700    *
701    * The values of that column are used to determine how many rows a value in 
702    * the list will span. Therefore, the values in the model column pointed to 
703    * by this property must be greater than zero and not larger than wrap-width.
704    *
705    * Since: 2.4
706    */
707   g_object_class_install_property (object_class,
708                                    PROP_ROW_SPAN_COLUMN,
709                                    g_param_spec_int ("row-span-column",
710                                                      P_("Row span column"),
711                                                      P_("TreeModel column containing the row span values"),
712                                                      -1,
713                                                      G_MAXINT,
714                                                      -1,
715                                                      GTK_PARAM_READWRITE));
716
717
718   /**
719    * GtkComboBox:column-span-column:
720    *
721    * If this is set to a non-negative value, it must be the index of a column 
722    * of type %G_TYPE_INT in the model. 
723    *
724    * The values of that column are used to determine how many columns a value 
725    * in the list will span. 
726    *
727    * Since: 2.4
728    */
729   g_object_class_install_property (object_class,
730                                    PROP_COLUMN_SPAN_COLUMN,
731                                    g_param_spec_int ("column-span-column",
732                                                      P_("Column span column"),
733                                                      P_("TreeModel column containing the column span values"),
734                                                      -1,
735                                                      G_MAXINT,
736                                                      -1,
737                                                      GTK_PARAM_READWRITE));
738
739
740   /**
741    * GtkComboBox:active:
742    *
743    * The item which is currently active. If the model is a non-flat treemodel,
744    * and the active item is not an immediate child of the root of the tree,
745    * this property has the value 
746    * <literal>gtk_tree_path_get_indices (path)[0]</literal>,
747    * where <literal>path</literal> is the #GtkTreePath of the active item.
748    *
749    * Since: 2.4
750    */
751   g_object_class_install_property (object_class,
752                                    PROP_ACTIVE,
753                                    g_param_spec_int ("active",
754                                                      P_("Active item"),
755                                                      P_("The item which is currently active"),
756                                                      -1,
757                                                      G_MAXINT,
758                                                      -1,
759                                                      GTK_PARAM_READWRITE));
760
761   /**
762    * GtkComboBox:add-tearoffs:
763    *
764    * The add-tearoffs property controls whether generated menus 
765    * have tearoff menu items. 
766    *
767    * Note that this only affects menu style combo boxes.
768    *
769    * Since: 2.6
770    */
771   g_object_class_install_property (object_class,
772                                    PROP_ADD_TEAROFFS,
773                                    g_param_spec_boolean ("add-tearoffs",
774                                                          P_("Add tearoffs to menus"),
775                                                          P_("Whether dropdowns should have a tearoff menu item"),
776                                                          FALSE,
777                                                          GTK_PARAM_READWRITE));
778   
779   /**
780    * GtkComboBox:has-frame:
781    *
782    * The has-frame property controls whether a frame
783    * is drawn around the entry.
784    *
785    * Since: 2.6
786    */
787   g_object_class_install_property (object_class,
788                                    PROP_HAS_FRAME,
789                                    g_param_spec_boolean ("has-frame",
790                                                          P_("Has Frame"),
791                                                          P_("Whether the combo box draws a frame around the child"),
792                                                          TRUE,
793                                                          GTK_PARAM_READWRITE));
794   
795   g_object_class_install_property (object_class,
796                                    PROP_FOCUS_ON_CLICK,
797                                    g_param_spec_boolean ("focus-on-click",
798                                                          P_("Focus on click"),
799                                                          P_("Whether the combo box grabs focus when it is clicked with the mouse"),
800                                                          TRUE,
801                                                          GTK_PARAM_READWRITE));
802
803   /**
804    * GtkComboBox:tearoff-title:
805    *
806    * A title that may be displayed by the window manager 
807    * when the popup is torn-off.
808    *
809    * Since: 2.10
810    */
811   g_object_class_install_property (object_class,
812                                    PROP_TEAROFF_TITLE,
813                                    g_param_spec_string ("tearoff-title",
814                                                         P_("Tearoff Title"),
815                                                         P_("A title that may be displayed by the window manager when the popup is torn-off"),
816                                                         NULL,
817                                                         GTK_PARAM_READWRITE));
818
819
820   /**
821    * GtkComboBox:popup-shown:
822    *
823    * Whether the combo boxes dropdown is popped up. 
824    * Note that this property is mainly useful, because
825    * it allows you to connect to notify::popup-shown.
826    *
827    * Since: 2.10
828    */
829   g_object_class_install_property (object_class,
830                                    PROP_POPUP_SHOWN,
831                                    g_param_spec_boolean ("popup-shown",
832                                                          P_("Popup shown"),
833                                                          P_("Whether the combo's dropdown is shown"),
834                                                          FALSE,
835                                                          GTK_PARAM_READABLE));
836
837
838    /**
839     * GtkComboBox:button-sensitivity:
840     *
841     * Whether the dropdown button is sensitive when
842     * the model is empty.
843     *
844     * Since: 2.14
845     */
846    g_object_class_install_property (object_class,
847                                     PROP_BUTTON_SENSITIVITY,
848                                     g_param_spec_enum ("button-sensitivity",
849                                                        P_("Button Sensitivity"),
850                                                        P_("Whether the dropdown button is sensitive when the model is empty"),
851                                                        GTK_TYPE_SENSITIVITY_TYPE,
852                                                        GTK_SENSITIVITY_AUTO,
853                                                        GTK_PARAM_READWRITE));
854
855   gtk_widget_class_install_style_property (widget_class,
856                                            g_param_spec_boolean ("appears-as-list",
857                                                                  P_("Appears as list"),
858                                                                  P_("Whether dropdowns should look like lists rather than menus"),
859                                                                  FALSE,
860                                                                  GTK_PARAM_READABLE));
861
862   /**
863    * GtkComboBox:arrow-size:
864    *
865    * Sets the minimum size of the arrow in the combo box.  Note
866    * that the arrow size is coupled to the font size, so in case
867    * a larger font is used, the arrow will be larger than set
868    * by arrow size.
869    *
870    * Since: 2.12
871    */
872   gtk_widget_class_install_style_property (widget_class,
873                                            g_param_spec_int ("arrow-size",
874                                                              P_("Arrow Size"),
875                                                              P_("The minimum size of the arrow in the combo box"),
876                                                              0,
877                                                              G_MAXINT,
878                                                              15,
879                                                              GTK_PARAM_READABLE));
880
881   /**
882    * GtkComboBox:shadow-type:
883    *
884    * Which kind of shadow to draw around the combo box.
885    *
886    * Since: 2.12
887    */
888   gtk_widget_class_install_style_property (widget_class,
889                                            g_param_spec_enum ("shadow-type",
890                                                               P_("Shadow type"),
891                                                               P_("Which kind of shadow to draw around the combo box"),
892                                                               GTK_TYPE_SHADOW_TYPE,
893                                                               GTK_SHADOW_NONE,
894                                                               GTK_PARAM_READABLE));
895
896   g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
897 }
898
899 static void
900 gtk_combo_box_buildable_init (GtkBuildableIface *iface)
901 {
902   parent_buildable_iface = g_type_interface_peek_parent (iface);
903   iface->add_child = _gtk_cell_layout_buildable_add_child;
904   iface->custom_tag_start = gtk_combo_box_buildable_custom_tag_start;
905   iface->custom_tag_end = gtk_combo_box_buildable_custom_tag_end;
906 }
907
908 static void
909 gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
910 {
911   iface->pack_start = gtk_combo_box_cell_layout_pack_start;
912   iface->pack_end = gtk_combo_box_cell_layout_pack_end;
913   iface->get_cells = gtk_combo_box_cell_layout_get_cells;
914   iface->clear = gtk_combo_box_cell_layout_clear;
915   iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
916   iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
917   iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
918   iface->reorder = gtk_combo_box_cell_layout_reorder;
919 }
920
921 static void
922 gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface)
923 {
924   iface->start_editing = gtk_combo_box_start_editing;
925 }
926
927 static void
928 gtk_combo_box_init (GtkComboBox *combo_box)
929 {
930   GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
931
932   priv->cell_view = gtk_cell_view_new ();
933   gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (combo_box));
934   GTK_BIN (combo_box)->child = priv->cell_view;
935   gtk_widget_show (priv->cell_view);
936
937   priv->width = 0;
938   priv->height = 0;
939   priv->wrap_width = 0;
940
941   priv->active = -1;
942   priv->active_row = NULL;
943   priv->col_column = -1;
944   priv->row_column = -1;
945
946   priv->popup_shown = FALSE;
947   priv->add_tearoffs = FALSE;
948   priv->has_frame = TRUE;
949   priv->is_cell_renderer = FALSE;
950   priv->editing_canceled = FALSE;
951   priv->auto_scroll = FALSE;
952   priv->focus_on_click = TRUE;
953   priv->button_sensitivity = GTK_SENSITIVITY_AUTO;
954
955   combo_box->priv = priv;
956
957   gtk_combo_box_check_appearance (combo_box);
958 }
959
960 static void
961 gtk_combo_box_set_property (GObject      *object,
962                             guint         prop_id,
963                             const GValue *value,
964                             GParamSpec   *pspec)
965 {
966   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
967
968   switch (prop_id)
969     {
970     case PROP_MODEL:
971       gtk_combo_box_set_model (combo_box, g_value_get_object (value));
972       break;
973
974     case PROP_WRAP_WIDTH:
975       gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
976       break;
977
978     case PROP_ROW_SPAN_COLUMN:
979       gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
980       break;
981
982     case PROP_COLUMN_SPAN_COLUMN:
983       gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
984       break;
985
986     case PROP_ACTIVE:
987       gtk_combo_box_set_active (combo_box, g_value_get_int (value));
988       break;
989
990     case PROP_ADD_TEAROFFS:
991       gtk_combo_box_set_add_tearoffs (combo_box, g_value_get_boolean (value));
992       break;
993
994     case PROP_HAS_FRAME:
995       combo_box->priv->has_frame = g_value_get_boolean (value);
996       break;
997
998     case PROP_FOCUS_ON_CLICK:
999       gtk_combo_box_set_focus_on_click (combo_box,
1000                                         g_value_get_boolean (value));
1001       break;
1002
1003     case PROP_TEAROFF_TITLE:
1004       gtk_combo_box_set_title (combo_box, g_value_get_string (value));
1005       break;
1006
1007     case PROP_POPUP_SHOWN:
1008       if (g_value_get_boolean (value))
1009         gtk_combo_box_popup (combo_box);
1010       else
1011         gtk_combo_box_popdown (combo_box);
1012       break;
1013
1014     case PROP_BUTTON_SENSITIVITY:
1015       gtk_combo_box_set_button_sensitivity (combo_box,
1016                                             g_value_get_enum (value));
1017       break;
1018
1019     case PROP_EDITING_CANCELED:
1020       combo_box->priv->editing_canceled = g_value_get_boolean (value);
1021       break;
1022
1023     default:
1024       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1025       break;
1026     }
1027 }
1028
1029 static void
1030 gtk_combo_box_get_property (GObject    *object,
1031                             guint       prop_id,
1032                             GValue     *value,
1033                             GParamSpec *pspec)
1034 {
1035   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
1036   GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
1037
1038   switch (prop_id)
1039     {
1040       case PROP_MODEL:
1041         g_value_set_object (value, combo_box->priv->model);
1042         break;
1043
1044       case PROP_WRAP_WIDTH:
1045         g_value_set_int (value, combo_box->priv->wrap_width);
1046         break;
1047
1048       case PROP_ROW_SPAN_COLUMN:
1049         g_value_set_int (value, combo_box->priv->row_column);
1050         break;
1051
1052       case PROP_COLUMN_SPAN_COLUMN:
1053         g_value_set_int (value, combo_box->priv->col_column);
1054         break;
1055
1056       case PROP_ACTIVE:
1057         g_value_set_int (value, gtk_combo_box_get_active (combo_box));
1058         break;
1059
1060       case PROP_ADD_TEAROFFS:
1061         g_value_set_boolean (value, gtk_combo_box_get_add_tearoffs (combo_box));
1062         break;
1063
1064       case PROP_HAS_FRAME:
1065         g_value_set_boolean (value, combo_box->priv->has_frame);
1066         break;
1067
1068       case PROP_FOCUS_ON_CLICK:
1069         g_value_set_boolean (value, combo_box->priv->focus_on_click);
1070         break;
1071
1072       case PROP_TEAROFF_TITLE:
1073         g_value_set_string (value, gtk_combo_box_get_title (combo_box));
1074         break;
1075
1076       case PROP_POPUP_SHOWN:
1077         g_value_set_boolean (value, combo_box->priv->popup_shown);
1078         break;
1079
1080       case PROP_BUTTON_SENSITIVITY:
1081         g_value_set_enum (value, combo_box->priv->button_sensitivity);
1082         break;
1083
1084       case PROP_EDITING_CANCELED:
1085         g_value_set_boolean (value, priv->editing_canceled);
1086         break;
1087
1088       default:
1089         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1090         break;
1091     }
1092 }
1093
1094 static void
1095 gtk_combo_box_state_changed (GtkWidget    *widget,
1096                              GtkStateType  previous)
1097 {
1098   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1099   GtkComboBoxPrivate *priv = combo_box->priv;
1100
1101   if (gtk_widget_get_realized (widget))
1102     {
1103       if (priv->tree_view && priv->cell_view)
1104         gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
1105                                             &widget->style->base[gtk_widget_get_state (widget)]);
1106     }
1107
1108   gtk_widget_queue_draw (widget);
1109 }
1110
1111 static void
1112 gtk_combo_box_button_state_changed (GtkWidget    *widget,
1113                                     GtkStateType  previous,
1114                                     gpointer      data)
1115 {
1116   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1117   GtkComboBoxPrivate *priv = combo_box->priv;
1118
1119   if (gtk_widget_get_realized (widget))
1120     {
1121       if (!priv->tree_view && priv->cell_view)
1122         {
1123           if ((gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE) !=
1124               (gtk_widget_get_state (priv->cell_view) == GTK_STATE_INSENSITIVE))
1125             gtk_widget_set_sensitive (priv->cell_view, gtk_widget_get_sensitive (widget));
1126           
1127           gtk_widget_set_state (priv->cell_view, 
1128                                 gtk_widget_get_state (widget));
1129         }
1130     }
1131
1132   gtk_widget_queue_draw (widget);
1133 }
1134
1135 static void
1136 gtk_combo_box_check_appearance (GtkComboBox *combo_box)
1137 {
1138   GtkComboBoxPrivate *priv = combo_box->priv;
1139   gboolean appears_as_list;
1140
1141   /* if wrap_width > 0, then we are in grid-mode and forced to use
1142    * unix style
1143    */
1144   if (priv->wrap_width)
1145     appears_as_list = FALSE;
1146   else
1147     gtk_widget_style_get (GTK_WIDGET (combo_box),
1148                           "appears-as-list", &appears_as_list,
1149                           NULL);
1150
1151   if (appears_as_list)
1152     {
1153       /* Destroy all the menu mode widgets, if they exist. */
1154       if (GTK_IS_MENU (priv->popup_widget))
1155         gtk_combo_box_menu_destroy (combo_box);
1156
1157       /* Create the list mode widgets, if they don't already exist. */
1158       if (!GTK_IS_TREE_VIEW (priv->tree_view))
1159         gtk_combo_box_list_setup (combo_box);
1160     }
1161   else
1162     {
1163       /* Destroy all the list mode widgets, if they exist. */
1164       if (GTK_IS_TREE_VIEW (priv->tree_view))
1165         gtk_combo_box_list_destroy (combo_box);
1166
1167       /* Create the menu mode widgets, if they don't already exist. */
1168       if (!GTK_IS_MENU (priv->popup_widget))
1169         gtk_combo_box_menu_setup (combo_box, TRUE);
1170     }
1171
1172   gtk_widget_style_get (GTK_WIDGET (combo_box),
1173                         "shadow-type", &priv->shadow_type,
1174                         NULL);
1175 }
1176
1177 static void
1178 gtk_combo_box_style_set (GtkWidget *widget,
1179                          GtkStyle  *previous)
1180 {
1181   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1182   GtkComboBoxPrivate *priv = combo_box->priv;
1183
1184   gtk_combo_box_check_appearance (combo_box);
1185
1186   if (priv->tree_view && priv->cell_view)
1187     gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
1188                                         &widget->style->base[gtk_widget_get_state (widget)]);
1189
1190   if (GTK_IS_ENTRY (GTK_BIN (combo_box)->child))
1191     g_object_set (GTK_BIN (combo_box)->child, "shadow-type",
1192                   GTK_SHADOW_NONE == priv->shadow_type ?
1193                   GTK_SHADOW_IN : GTK_SHADOW_NONE, NULL);
1194 }
1195
1196 static void
1197 gtk_combo_box_button_toggled (GtkWidget *widget,
1198                               gpointer   data)
1199 {
1200   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1201
1202   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
1203     {
1204       if (!combo_box->priv->popup_in_progress)
1205         gtk_combo_box_popup (combo_box);
1206     }
1207   else
1208     gtk_combo_box_popdown (combo_box);
1209 }
1210
1211 static void
1212 gtk_combo_box_add (GtkContainer *container,
1213                    GtkWidget    *widget)
1214 {
1215   GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1216   GtkComboBoxPrivate *priv = combo_box->priv;
1217
1218   if (priv->cell_view && priv->cell_view->parent)
1219     {
1220       gtk_widget_unparent (priv->cell_view);
1221       GTK_BIN (container)->child = NULL;
1222       gtk_widget_queue_resize (GTK_WIDGET (container));
1223     }
1224   
1225   gtk_widget_set_parent (widget, GTK_WIDGET (container));
1226   GTK_BIN (container)->child = widget;
1227
1228   if (priv->cell_view &&
1229       widget != priv->cell_view)
1230     {
1231       /* since the cell_view was unparented, it's gone now */
1232       priv->cell_view = NULL;
1233
1234       if (!priv->tree_view && priv->separator)
1235         {
1236           gtk_container_remove (GTK_CONTAINER (priv->separator->parent),
1237                                 priv->separator);
1238           priv->separator = NULL;
1239
1240           gtk_widget_queue_resize (GTK_WIDGET (container));
1241         }
1242       else if (priv->cell_view_frame)
1243         {
1244           gtk_widget_unparent (priv->cell_view_frame);
1245           priv->cell_view_frame = NULL;
1246           priv->box = NULL;
1247         }
1248     }
1249 }
1250
1251 static void
1252 gtk_combo_box_remove (GtkContainer *container,
1253                       GtkWidget    *widget)
1254 {
1255   GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1256   GtkComboBoxPrivate *priv = combo_box->priv;
1257   GtkTreePath *path;
1258   gboolean appears_as_list;
1259
1260   if (widget == priv->cell_view)
1261     priv->cell_view = NULL;
1262
1263   gtk_widget_unparent (widget);
1264   GTK_BIN (container)->child = NULL;
1265
1266   if (GTK_OBJECT_FLAGS (combo_box) & GTK_IN_DESTRUCTION)
1267     return;
1268
1269   gtk_widget_queue_resize (GTK_WIDGET (container));
1270
1271   if (!priv->tree_view)
1272     appears_as_list = FALSE;
1273   else
1274     appears_as_list = TRUE;
1275   
1276   if (appears_as_list)
1277     gtk_combo_box_list_destroy (combo_box);
1278   else if (GTK_IS_MENU (priv->popup_widget))
1279     {
1280       gtk_combo_box_menu_destroy (combo_box);
1281       gtk_menu_detach (GTK_MENU (priv->popup_widget));
1282       priv->popup_widget = NULL;
1283     }
1284
1285   if (!priv->cell_view)
1286     {
1287       priv->cell_view = gtk_cell_view_new ();
1288       gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (container));
1289       GTK_BIN (container)->child = priv->cell_view;
1290       
1291       gtk_widget_show (priv->cell_view);
1292       gtk_cell_view_set_model (GTK_CELL_VIEW (priv->cell_view),
1293                                priv->model);
1294       gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (priv->cell_view));
1295     }
1296
1297
1298   if (appears_as_list)
1299     gtk_combo_box_list_setup (combo_box); 
1300   else
1301     gtk_combo_box_menu_setup (combo_box, TRUE);
1302
1303   if (gtk_tree_row_reference_valid (priv->active_row))
1304     {
1305       path = gtk_tree_row_reference_get_path (priv->active_row);
1306       gtk_combo_box_set_active_internal (combo_box, path);
1307       gtk_tree_path_free (path);
1308     }
1309   else
1310     gtk_combo_box_set_active_internal (combo_box, NULL);
1311 }
1312
1313 static ComboCellInfo *
1314 gtk_combo_box_get_cell_info (GtkComboBox     *combo_box,
1315                              GtkCellRenderer *cell)
1316 {
1317   GSList *i;
1318
1319   for (i = combo_box->priv->cells; i; i = i->next)
1320     {
1321       ComboCellInfo *info = (ComboCellInfo *)i->data;
1322
1323       if (info && info->cell == cell)
1324         return info;
1325     }
1326
1327   return NULL;
1328 }
1329
1330 static void
1331 gtk_combo_box_menu_show (GtkWidget *menu,
1332                          gpointer   user_data)
1333 {
1334   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1335   GtkComboBoxPrivate *priv = combo_box->priv;
1336
1337   gtk_combo_box_child_show (menu, user_data);
1338
1339   priv->popup_in_progress = TRUE;
1340   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
1341                                 TRUE);
1342   priv->popup_in_progress = FALSE;
1343 }
1344
1345 static void
1346 gtk_combo_box_menu_hide (GtkWidget *menu,
1347                          gpointer   user_data)
1348 {
1349   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1350
1351   gtk_combo_box_child_hide (menu,user_data);
1352
1353   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
1354                                 FALSE);
1355 }
1356
1357 static void
1358 gtk_combo_box_detacher (GtkWidget *widget,
1359                         GtkMenu   *menu)
1360 {
1361   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1362   GtkComboBoxPrivate *priv = combo_box->priv;
1363
1364   g_return_if_fail (priv->popup_widget == (GtkWidget *) menu);
1365
1366   g_signal_handlers_disconnect_by_func (menu->toplevel,
1367                                         gtk_combo_box_menu_show,
1368                                         combo_box);
1369   g_signal_handlers_disconnect_by_func (menu->toplevel,
1370                                         gtk_combo_box_menu_hide,
1371                                         combo_box);
1372   
1373   priv->popup_widget = NULL;
1374 }
1375
1376 static void
1377 gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
1378                                 GtkWidget   *popup)
1379 {
1380   GtkComboBoxPrivate *priv = combo_box->priv;
1381
1382   if (GTK_IS_MENU (priv->popup_widget))
1383     {
1384       gtk_menu_detach (GTK_MENU (priv->popup_widget));
1385       priv->popup_widget = NULL;
1386     }
1387   else if (priv->popup_widget)
1388     {
1389       gtk_container_remove (GTK_CONTAINER (priv->scrolled_window),
1390                             priv->popup_widget);
1391       g_object_unref (priv->popup_widget);
1392       priv->popup_widget = NULL;
1393     }
1394
1395   if (GTK_IS_MENU (popup))
1396     {
1397       if (priv->popup_window)
1398         {
1399           gtk_widget_destroy (priv->popup_window);
1400           priv->popup_window = NULL;
1401         }
1402
1403       priv->popup_widget = popup;
1404
1405       /* 
1406        * Note that we connect to show/hide on the toplevel, not the
1407        * menu itself, since the menu is not shown/hidden when it is
1408        * popped up while torn-off.
1409        */
1410       g_signal_connect (GTK_MENU (popup)->toplevel, "show",
1411                         G_CALLBACK (gtk_combo_box_menu_show), combo_box);
1412       g_signal_connect (GTK_MENU (popup)->toplevel, "hide",
1413                         G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
1414
1415       gtk_menu_attach_to_widget (GTK_MENU (popup),
1416                                  GTK_WIDGET (combo_box),
1417                                  gtk_combo_box_detacher);
1418     }
1419   else
1420     {
1421       if (!priv->popup_window)
1422         {
1423           GtkWidget *toplevel;
1424           
1425           priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
1426           gtk_widget_set_name (priv->popup_window, "gtk-combobox-popup-window");
1427
1428           gtk_window_set_type_hint (GTK_WINDOW (priv->popup_window),
1429                                     GDK_WINDOW_TYPE_HINT_COMBO);
1430
1431           g_signal_connect (GTK_WINDOW (priv->popup_window),"show",
1432                             G_CALLBACK (gtk_combo_box_child_show),
1433                             combo_box);
1434           g_signal_connect (GTK_WINDOW (priv->popup_window),"hide",
1435                             G_CALLBACK (gtk_combo_box_child_hide),
1436                             combo_box);
1437           
1438           toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo_box));
1439           if (GTK_IS_WINDOW (toplevel))
1440             {
1441               gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)), 
1442                                            GTK_WINDOW (priv->popup_window));
1443               gtk_window_set_transient_for (GTK_WINDOW (priv->popup_window),
1444                                             GTK_WINDOW (toplevel));
1445             }
1446
1447           gtk_window_set_resizable (GTK_WINDOW (priv->popup_window), FALSE);
1448           gtk_window_set_screen (GTK_WINDOW (priv->popup_window),
1449                                  gtk_widget_get_screen (GTK_WIDGET (combo_box)));
1450
1451           priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1452           
1453           gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
1454                                           GTK_POLICY_NEVER,
1455                                           GTK_POLICY_NEVER);
1456           gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window),
1457                                                GTK_SHADOW_IN);
1458
1459           gtk_widget_show (priv->scrolled_window);
1460           
1461           gtk_container_add (GTK_CONTAINER (priv->popup_window),
1462                              priv->scrolled_window);
1463         }
1464
1465       gtk_container_add (GTK_CONTAINER (priv->scrolled_window),
1466                          popup);
1467
1468       gtk_widget_show (popup);
1469       g_object_ref (popup);
1470       priv->popup_widget = popup;
1471     }
1472 }
1473
1474 static void
1475 gtk_combo_box_menu_position_below (GtkMenu  *menu,
1476                                    gint     *x,
1477                                    gint     *y,
1478                                    gint     *push_in,
1479                                    gpointer  user_data)
1480 {
1481   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1482   gint sx, sy;
1483   GtkWidget *child;
1484   GtkRequisition req;
1485   GdkScreen *screen;
1486   gint monitor_num;
1487   GdkRectangle monitor;
1488   
1489   /* FIXME: is using the size request here broken? */
1490   child = GTK_BIN (combo_box)->child;
1491
1492   sx = sy = 0;
1493
1494   if (!gtk_widget_get_has_window (child))
1495     {
1496       sx += child->allocation.x;
1497       sy += child->allocation.y;
1498     }
1499
1500   gdk_window_get_root_coords (child->window, sx, sy, &sx, &sy);
1501
1502   if (GTK_SHADOW_NONE != combo_box->priv->shadow_type)
1503     sx -= GTK_WIDGET (combo_box)->style->xthickness;
1504
1505   gtk_widget_size_request (GTK_WIDGET (menu), &req);
1506
1507   if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR)
1508     *x = sx;
1509   else
1510     *x = sx + child->allocation.width - req.width;
1511   *y = sy;
1512
1513   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
1514   monitor_num = gdk_screen_get_monitor_at_window (screen, 
1515                                                   GTK_WIDGET (combo_box)->window);
1516   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1517   
1518   if (*x < monitor.x)
1519     *x = monitor.x;
1520   else if (*x + req.width > monitor.x + monitor.width)
1521     *x = monitor.x + monitor.width - req.width;
1522   
1523   if (monitor.y + monitor.height - *y - child->allocation.height >= req.height)
1524     *y += child->allocation.height;
1525   else if (*y - monitor.y >= req.height)
1526     *y -= req.height;
1527   else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y) 
1528     *y += child->allocation.height;
1529   else
1530     *y -= req.height;
1531
1532    *push_in = FALSE;
1533 }
1534
1535 static void
1536 gtk_combo_box_menu_position_over (GtkMenu  *menu,
1537                                   gint     *x,
1538                                   gint     *y,
1539                                   gboolean *push_in,
1540                                   gpointer  user_data)
1541 {
1542   GtkComboBox *combo_box;
1543   GtkWidget *active;
1544   GtkWidget *child;
1545   GtkWidget *widget;
1546   GtkRequisition requisition;
1547   GList *children;
1548   gint screen_width;
1549   gint menu_xpos;
1550   gint menu_ypos;
1551   gint menu_width;
1552
1553   combo_box = GTK_COMBO_BOX (user_data);
1554   widget = GTK_WIDGET (combo_box);
1555
1556   gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition);
1557   menu_width = requisition.width;
1558
1559   active = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget));
1560
1561   menu_xpos = widget->allocation.x;
1562   menu_ypos = widget->allocation.y + widget->allocation.height / 2 - 2;
1563
1564   if (active != NULL)
1565     {
1566       gtk_widget_get_child_requisition (active, &requisition);
1567       menu_ypos -= requisition.height / 2;
1568     }
1569
1570   children = GTK_MENU_SHELL (combo_box->priv->popup_widget)->children;
1571   while (children)
1572     {
1573       child = children->data;
1574
1575       if (active == child)
1576         break;
1577
1578       if (gtk_widget_get_visible (child))
1579         {
1580           gtk_widget_get_child_requisition (child, &requisition);
1581           menu_ypos -= requisition.height;
1582         }
1583
1584       children = children->next;
1585     }
1586
1587   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1588     menu_xpos = menu_xpos + widget->allocation.width - menu_width;
1589
1590   gdk_window_get_root_coords (widget->window, menu_xpos, menu_ypos,
1591                               &menu_xpos, &menu_ypos);
1592
1593   /* Clamp the position on screen */
1594   screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));
1595   
1596   if (menu_xpos < 0)
1597     menu_xpos = 0;
1598   else if ((menu_xpos + menu_width) > screen_width)
1599     menu_xpos -= ((menu_xpos + menu_width) - screen_width);
1600
1601   *x = menu_xpos;
1602   *y = menu_ypos;
1603
1604   *push_in = TRUE;
1605 }
1606
1607 static void
1608 gtk_combo_box_menu_position (GtkMenu  *menu,
1609                              gint     *x,
1610                              gint     *y,
1611                              gint     *push_in,
1612                              gpointer  user_data)
1613 {
1614   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
1615   GtkComboBoxPrivate *priv = combo_box->priv;
1616   GtkWidget *menu_item;
1617
1618
1619   if (priv->wrap_width > 0 || priv->cell_view == NULL)  
1620     gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data);
1621   else
1622     {
1623       /* FIXME handle nested menus better */
1624       menu_item = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
1625       if (menu_item)
1626         gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->popup_widget), 
1627                                     menu_item);
1628
1629       gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
1630     }
1631
1632   if (!gtk_widget_get_visible (GTK_MENU (priv->popup_widget)->toplevel))
1633     gtk_window_set_type_hint (GTK_WINDOW (GTK_MENU (priv->popup_widget)->toplevel),
1634                               GDK_WINDOW_TYPE_HINT_COMBO);
1635 }
1636
1637 static void
1638 gtk_combo_box_list_position (GtkComboBox *combo_box, 
1639                              gint        *x, 
1640                              gint        *y, 
1641                              gint        *width,
1642                              gint        *height)
1643 {
1644   GtkComboBoxPrivate *priv = combo_box->priv;
1645   GdkScreen *screen;
1646   gint monitor_num;
1647   GdkRectangle monitor;
1648   GtkRequisition popup_req;
1649   GtkPolicyType hpolicy, vpolicy;
1650   
1651   /* under windows, the drop down list is as wide as the combo box itself.
1652      see bug #340204 */
1653   GtkWidget *sample = GTK_WIDGET (combo_box);
1654
1655   *x = *y = 0;
1656
1657   if (!gtk_widget_get_has_window (sample))
1658     {
1659       *x += sample->allocation.x;
1660       *y += sample->allocation.y;
1661     }
1662   
1663   gdk_window_get_root_coords (sample->window, *x, *y, x, y);
1664
1665   *width = sample->allocation.width;
1666
1667   hpolicy = vpolicy = GTK_POLICY_NEVER;
1668   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
1669                                   hpolicy, vpolicy);
1670   gtk_widget_size_request (priv->scrolled_window, &popup_req);
1671
1672   if (popup_req.width > *width)
1673     {
1674       hpolicy = GTK_POLICY_ALWAYS;
1675       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
1676                                       hpolicy, vpolicy);
1677       gtk_widget_size_request (priv->scrolled_window, &popup_req);
1678     }
1679
1680   *height = popup_req.height;
1681
1682   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
1683   monitor_num = gdk_screen_get_monitor_at_window (screen, 
1684                                                   GTK_WIDGET (combo_box)->window);
1685   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1686
1687   if (*x < monitor.x)
1688     *x = monitor.x;
1689   else if (*x + *width > monitor.x + monitor.width)
1690     *x = monitor.x + monitor.width - *width;
1691   
1692   if (*y + sample->allocation.height + *height <= monitor.y + monitor.height)
1693     *y += sample->allocation.height;
1694   else if (*y - *height >= monitor.y)
1695     *y -= *height;
1696   else if (monitor.y + monitor.height - (*y + sample->allocation.height) > *y - monitor.y)
1697     {
1698       *y += sample->allocation.height;
1699       *height = monitor.y + monitor.height - *y;
1700     }
1701   else 
1702     {
1703       *height = *y - monitor.y;
1704       *y = monitor.y;
1705     }
1706
1707   if (popup_req.height > *height)
1708     {
1709       vpolicy = GTK_POLICY_ALWAYS;
1710       
1711       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
1712                                       hpolicy, vpolicy);
1713     }
1714
1715
1716 static gboolean
1717 cell_view_is_sensitive (GtkCellView *cell_view)
1718 {
1719   GList *cells, *list;
1720   gboolean sensitive;
1721   
1722   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view));
1723
1724   sensitive = FALSE;
1725   for (list = cells; list; list = list->next)
1726     {
1727       g_object_get (list->data, "sensitive", &sensitive, NULL);
1728       
1729       if (sensitive)
1730         break;
1731     }
1732   g_list_free (cells);
1733
1734   return sensitive;
1735 }
1736
1737 static gboolean
1738 tree_column_row_is_sensitive (GtkComboBox *combo_box,
1739                               GtkTreeIter *iter)
1740 {
1741   GtkComboBoxPrivate *priv = combo_box->priv;
1742   GList *cells, *list;
1743   gboolean sensitive;
1744
1745   if (!priv->column)
1746     return TRUE;
1747
1748   if (priv->row_separator_func)
1749     {
1750       if (priv->row_separator_func (priv->model, iter,
1751                                     priv->row_separator_data))
1752         return FALSE;
1753     }
1754
1755   gtk_tree_view_column_cell_set_cell_data (priv->column,
1756                                            priv->model,
1757                                            iter, FALSE, FALSE);
1758
1759   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->column));
1760
1761   sensitive = FALSE;
1762   for (list = cells; list; list = list->next)
1763     {
1764       g_object_get (list->data, "sensitive", &sensitive, NULL);
1765       
1766       if (sensitive)
1767         break;
1768     }
1769   g_list_free (cells);
1770
1771   return sensitive;
1772 }
1773
1774 static void
1775 update_menu_sensitivity (GtkComboBox *combo_box,
1776                          GtkWidget   *menu)
1777 {
1778   GtkComboBoxPrivate *priv = combo_box->priv;
1779   GList *children, *child;
1780   GtkWidget *item, *submenu, *separator;
1781   GtkWidget *cell_view;
1782   gboolean sensitive;
1783
1784   if (!priv->model)
1785     return;
1786
1787   children = gtk_container_get_children (GTK_CONTAINER (menu));
1788
1789   for (child = children; child; child = child->next)
1790     {
1791       item = GTK_WIDGET (child->data);
1792       cell_view = GTK_BIN (item)->child;
1793
1794       if (!GTK_IS_CELL_VIEW (cell_view))
1795         continue;
1796       
1797       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
1798       if (submenu != NULL)
1799         {
1800           gtk_widget_set_sensitive (item, TRUE);
1801           update_menu_sensitivity (combo_box, submenu);
1802         }
1803       else
1804         {
1805           sensitive = cell_view_is_sensitive (GTK_CELL_VIEW (cell_view));
1806
1807           if (menu != priv->popup_widget && child == children)
1808             {
1809               separator = GTK_WIDGET (child->next->data);
1810               g_object_set (item, "visible", sensitive, NULL);
1811               g_object_set (separator, "visible", sensitive, NULL);
1812             }
1813           else
1814             gtk_widget_set_sensitive (item, sensitive);
1815         }
1816     }
1817
1818   g_list_free (children);
1819 }
1820
1821 static void 
1822 gtk_combo_box_menu_popup (GtkComboBox *combo_box,
1823                           guint        button, 
1824                           guint32      activate_time)
1825 {
1826   GtkComboBoxPrivate *priv = combo_box->priv;
1827   GtkTreePath *path;
1828   gint active_item;
1829   GtkRequisition requisition;
1830   gint width;
1831   
1832   update_menu_sensitivity (combo_box, priv->popup_widget);
1833
1834   active_item = -1;
1835   if (gtk_tree_row_reference_valid (priv->active_row))
1836     {
1837       path = gtk_tree_row_reference_get_path (priv->active_row);
1838       active_item = gtk_tree_path_get_indices (path)[0];
1839       gtk_tree_path_free (path);
1840       
1841       if (priv->add_tearoffs)
1842         active_item++;
1843     }
1844
1845   /* FIXME handle nested menus better */
1846   gtk_menu_set_active (GTK_MENU (priv->popup_widget), active_item);
1847   
1848   if (priv->wrap_width == 0)
1849     {
1850       width = GTK_WIDGET (combo_box)->allocation.width;
1851       gtk_widget_set_size_request (priv->popup_widget, -1, -1);
1852       gtk_widget_size_request (priv->popup_widget, &requisition);
1853       
1854       gtk_widget_set_size_request (priv->popup_widget,
1855                                    MAX (width, requisition.width), -1);
1856     }
1857   
1858   gtk_menu_popup (GTK_MENU (priv->popup_widget),
1859                   NULL, NULL,
1860                   gtk_combo_box_menu_position, combo_box,
1861                   button, activate_time);
1862 }
1863
1864 static gboolean
1865 popup_grab_on_window (GdkWindow *window,
1866                       GdkDevice *keyboard,
1867                       GdkDevice *pointer,
1868                       guint32    activate_time)
1869 {
1870   if (keyboard &&
1871       gdk_device_grab (keyboard, window,
1872                        GDK_OWNERSHIP_WINDOW, TRUE,
1873                        GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
1874                        NULL, activate_time) != GDK_GRAB_SUCCESS)
1875     return FALSE;
1876
1877   if (pointer &&
1878       gdk_device_grab (pointer, window,
1879                        GDK_OWNERSHIP_WINDOW, TRUE,
1880                        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1881                        GDK_POINTER_MOTION_MASK,
1882                        NULL, activate_time) != GDK_GRAB_SUCCESS)
1883     {
1884       if (keyboard)
1885         gdk_device_ungrab (keyboard, activate_time);
1886
1887       return FALSE;
1888     }
1889
1890   return TRUE;
1891 }
1892
1893 /**
1894  * gtk_combo_box_popup:
1895  * @combo_box: a #GtkComboBox
1896  * 
1897  * Pops up the menu or dropdown list of @combo_box. 
1898  *
1899  * This function is mostly intended for use by accessibility technologies;
1900  * applications should have little use for it.
1901  *
1902  * Since: 2.4
1903  */
1904 void
1905 gtk_combo_box_popup (GtkComboBox *combo_box)
1906 {
1907   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
1908
1909   g_signal_emit (combo_box, combo_box_signals[POPUP], 0);
1910 }
1911
1912 /**
1913  * gtk_combo_box_popup_for_device:
1914  * @combo_box: a #GtkComboBox
1915  * @device: a #GdkDevice
1916  *
1917  * Pops up the menu or dropdown list of @combo_box, the popup window
1918  * will be grabbed so only @device and its associated pointer/keyboard
1919  * are the only #GdkDevice<!-- -->s able to send events to it.
1920  *
1921  * Since: 3.0
1922  **/
1923 void
1924 gtk_combo_box_popup_for_device (GtkComboBox *combo_box,
1925                                 GdkDevice   *device)
1926 {
1927   GtkComboBoxPrivate *priv = combo_box->priv;
1928   gint x, y, width, height;
1929   GtkTreePath *path = NULL, *ppath;
1930   GtkWidget *toplevel;
1931   GdkDevice *keyboard, *pointer;
1932   guint32 time;
1933
1934   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
1935   g_return_if_fail (GDK_IS_DEVICE (device));
1936
1937   if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
1938     return;
1939
1940   if (gtk_widget_get_mapped (priv->popup_widget))
1941     return;
1942
1943   if (priv->grab_pointer && priv->grab_keyboard)
1944     return;
1945
1946   time = gtk_get_current_event_time ();
1947
1948   if (device->source == GDK_SOURCE_KEYBOARD)
1949     {
1950       keyboard = device;
1951       pointer = gdk_device_get_associated_device (device);
1952     }
1953   else
1954     {
1955       pointer = device;
1956       keyboard = gdk_device_get_associated_device (device);
1957     }
1958
1959   if (GTK_IS_MENU (priv->popup_widget))
1960     {
1961       gtk_combo_box_menu_popup (combo_box, 
1962                                 priv->activate_button,
1963                                 priv->activate_time);
1964       return;
1965     }
1966
1967   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo_box));
1968   if (GTK_IS_WINDOW (toplevel))
1969     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)), 
1970                                  GTK_WINDOW (priv->popup_window));
1971
1972   gtk_widget_show_all (priv->scrolled_window);
1973   gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
1974   
1975   gtk_widget_set_size_request (priv->popup_window, width, height);  
1976   gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
1977
1978   if (gtk_tree_row_reference_valid (priv->active_row))
1979     {
1980       path = gtk_tree_row_reference_get_path (priv->active_row);
1981       ppath = gtk_tree_path_copy (path);
1982       if (gtk_tree_path_up (ppath))
1983         gtk_tree_view_expand_to_path (GTK_TREE_VIEW (priv->tree_view),
1984                                       ppath);
1985       gtk_tree_path_free (ppath);
1986     }
1987   gtk_tree_view_set_hover_expand (GTK_TREE_VIEW (priv->tree_view), 
1988                                   TRUE);
1989   
1990   /* popup */
1991   gtk_widget_show (priv->popup_window);
1992
1993   if (path)
1994     {
1995       gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->tree_view),
1996                                 path, NULL, FALSE);
1997       gtk_tree_path_free (path);
1998     }
1999
2000   gtk_widget_grab_focus (priv->popup_window);
2001   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
2002                                 TRUE);
2003
2004   if (!gtk_widget_has_focus (priv->tree_view))
2005     gtk_widget_grab_focus (priv->tree_view);
2006
2007   if (!popup_grab_on_window (priv->popup_window->window,
2008                              keyboard, pointer, time))
2009     {
2010       gtk_widget_hide (priv->popup_window);
2011       return;
2012     }
2013
2014   gtk_device_grab_add (priv->popup_window, pointer, TRUE);
2015   priv->grab_pointer = pointer;
2016   priv->grab_keyboard = keyboard;
2017 }
2018
2019 static void
2020 gtk_combo_box_real_popup (GtkComboBox *combo_box)
2021 {
2022   GdkDevice *device;
2023
2024   device = gtk_get_current_event_device ();
2025
2026   if (!device)
2027     {
2028       GdkDeviceManager *device_manager;
2029       GdkDisplay *display;
2030       GList *devices;
2031
2032       display = gtk_widget_get_display (GTK_WIDGET (combo_box));
2033       device_manager = gdk_display_get_device_manager (display);
2034
2035       /* No device was set, pick the first master device */
2036       devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
2037       device = devices->data;
2038       g_list_free (devices);
2039     }
2040
2041   gtk_combo_box_popup_for_device (combo_box, device);
2042 }
2043
2044 static gboolean
2045 gtk_combo_box_real_popdown (GtkComboBox *combo_box)
2046 {
2047   if (combo_box->priv->popup_shown)
2048     {
2049       gtk_combo_box_popdown (combo_box);
2050       return TRUE;
2051     }
2052
2053   return FALSE;
2054 }
2055
2056 /**
2057  * gtk_combo_box_popdown:
2058  * @combo_box: a #GtkComboBox
2059  * 
2060  * Hides the menu or dropdown list of @combo_box.
2061  *
2062  * This function is mostly intended for use by accessibility technologies;
2063  * applications should have little use for it.
2064  *
2065  * Since: 2.4
2066  */
2067 void
2068 gtk_combo_box_popdown (GtkComboBox *combo_box)
2069 {
2070   GtkComboBoxPrivate *priv = combo_box->priv;
2071
2072   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
2073
2074   if (GTK_IS_MENU (priv->popup_widget))
2075     {
2076       gtk_menu_popdown (GTK_MENU (priv->popup_widget));
2077       return;
2078     }
2079
2080   if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
2081     return;
2082
2083   gtk_device_grab_remove (priv->popup_window, priv->grab_pointer);
2084   gtk_widget_hide_all (priv->popup_window);
2085   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
2086                                 FALSE);
2087
2088   priv->grab_pointer = NULL;
2089   priv->grab_keyboard = NULL;
2090 }
2091
2092 static gint
2093 gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
2094                                     GtkTreePath *path)
2095 {
2096   GtkComboBoxPrivate *priv = combo_box->priv;
2097   gint padding;
2098   GtkRequisition req;
2099
2100   if (priv->cell_view)
2101     gtk_widget_style_get (priv->cell_view,
2102                           "focus-line-width", &padding,
2103                           NULL);
2104   else
2105     padding = 0;
2106
2107   /* add some pixels for good measure */
2108   padding += BONUS_PADDING;
2109
2110   if (priv->cell_view)
2111     gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view),
2112                                    path, &req);
2113   else
2114     req.width = 0;
2115
2116   return req.width + padding;
2117 }
2118
2119 static void
2120 gtk_combo_box_remeasure (GtkComboBox *combo_box)
2121 {
2122   GtkComboBoxPrivate *priv = combo_box->priv;
2123   GtkTreeIter iter;
2124   GtkTreePath *path;
2125
2126   if (!priv->model ||
2127       !gtk_tree_model_get_iter_first (priv->model, &iter))
2128     return;
2129
2130   priv->width = 0;
2131   priv->height = 0;
2132
2133   path = gtk_tree_path_new_from_indices (0, -1);
2134
2135   do
2136     {
2137       GtkRequisition req;
2138
2139       if (priv->cell_view)
2140         gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view), 
2141                                        path, &req);
2142       else
2143         {
2144           req.width = 0;
2145           req.height = 0;
2146         }
2147
2148       priv->width = MAX (priv->width, req.width);
2149       priv->height = MAX (priv->height, req.height);
2150
2151       gtk_tree_path_next (path);
2152     }
2153   while (gtk_tree_model_iter_next (priv->model, &iter));
2154
2155   gtk_tree_path_free (path);
2156 }
2157
2158 static void
2159 gtk_combo_box_size_request (GtkWidget      *widget,
2160                             GtkRequisition *requisition)
2161 {
2162   gint width, height;
2163   gint focus_width, focus_pad;
2164   gint font_size;
2165   gint arrow_size;
2166   GtkRequisition bin_req;
2167   PangoContext *context;
2168   PangoFontMetrics *metrics;
2169   PangoFontDescription *font_desc;
2170
2171   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
2172   GtkComboBoxPrivate *priv = combo_box->priv;
2173  
2174   /* common */
2175   gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
2176   gtk_combo_box_remeasure (combo_box);
2177   bin_req.width = MAX (bin_req.width, priv->width);
2178   bin_req.height = MAX (bin_req.height, priv->height);
2179
2180   gtk_widget_style_get (GTK_WIDGET (widget),
2181                         "focus-line-width", &focus_width,
2182                         "focus-padding", &focus_pad,
2183                         "arrow-size", &arrow_size,
2184                         NULL);
2185
2186   font_desc = GTK_BIN (widget)->child->style->font_desc;
2187   context = gtk_widget_get_pango_context (widget);
2188   metrics = pango_context_get_metrics (context, font_desc,
2189                                        pango_context_get_language (context));
2190   font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
2191                             pango_font_metrics_get_descent (metrics));
2192   pango_font_metrics_unref (metrics);
2193
2194   arrow_size = MAX (arrow_size, font_size);
2195
2196   gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
2197
2198   if (!priv->tree_view)
2199     {
2200       /* menu mode */
2201
2202       if (priv->cell_view)
2203         {
2204           GtkRequisition button_req, sep_req, arrow_req;
2205           gint border_width, xthickness, ythickness;
2206
2207           gtk_widget_size_request (priv->button, &button_req);
2208           border_width = GTK_CONTAINER (combo_box)->border_width;
2209           xthickness = priv->button->style->xthickness;
2210           ythickness = priv->button->style->ythickness;
2211
2212           bin_req.width = MAX (bin_req.width, priv->width);
2213           bin_req.height = MAX (bin_req.height, priv->height);
2214
2215           gtk_widget_size_request (priv->separator, &sep_req);
2216           gtk_widget_size_request (priv->arrow, &arrow_req);
2217
2218           height = MAX (sep_req.height, arrow_req.height);
2219           height = MAX (height, bin_req.height);
2220
2221           width = bin_req.width + sep_req.width + arrow_req.width;
2222
2223           height += 2*(border_width + ythickness + focus_width + focus_pad);
2224           width  += 2*(border_width + xthickness + focus_width + focus_pad);
2225
2226           requisition->width = width;
2227           requisition->height = height;
2228         }
2229       else
2230         {
2231           GtkRequisition but_req;
2232
2233           gtk_widget_size_request (priv->button, &but_req);
2234
2235           requisition->width = bin_req.width + but_req.width;
2236           requisition->height = MAX (bin_req.height, but_req.height);
2237         }
2238     }
2239   else
2240     {
2241       /* list mode */
2242       GtkRequisition button_req, frame_req;
2243
2244       /* sample + frame */
2245       *requisition = bin_req;
2246
2247       requisition->width += 2 * focus_width;
2248       
2249       if (priv->cell_view_frame)
2250         {
2251           gtk_widget_size_request (priv->cell_view_frame, &frame_req);
2252           if (priv->has_frame)
2253             {
2254               requisition->width += 2 *
2255                 (GTK_CONTAINER (priv->cell_view_frame)->border_width +
2256                  GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
2257               requisition->height += 2 *
2258                 (GTK_CONTAINER (priv->cell_view_frame)->border_width +
2259                  GTK_WIDGET (priv->cell_view_frame)->style->ythickness);
2260             }
2261         }
2262
2263       /* the button */
2264       gtk_widget_size_request (priv->button, &button_req);
2265
2266       requisition->height = MAX (requisition->height, button_req.height);
2267       requisition->width += button_req.width;
2268     }
2269
2270   if (GTK_SHADOW_NONE != priv->shadow_type)
2271     {
2272       requisition->height += 2 * widget->style->ythickness;
2273       requisition->width += 2 * widget->style->xthickness;
2274     }
2275 }
2276
2277 #define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON                                      \
2278   gtk_widget_size_request (combo_box->priv->button, &req);                      \
2279                                                                                 \
2280   if (is_rtl)                                                                   \
2281     child.x = allocation->x + shadow_width;                                     \
2282   else                                                                          \
2283     child.x = allocation->x + allocation->width - req.width - shadow_width;     \
2284                                                                                 \
2285   child.y = allocation->y + shadow_height;                                      \
2286   child.width = req.width;                                                      \
2287   child.height = allocation->height - 2 * shadow_height;                        \
2288   child.width = MAX (1, child.width);                                           \
2289   child.height = MAX (1, child.height);                                         \
2290                                                                                 \
2291   gtk_widget_size_allocate (combo_box->priv->button, &child);
2292
2293 static void
2294 gtk_combo_box_size_allocate (GtkWidget     *widget,
2295                              GtkAllocation *allocation)
2296 {
2297   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
2298   GtkComboBoxPrivate *priv = combo_box->priv;
2299   gint shadow_width, shadow_height;
2300   gint focus_width, focus_pad;
2301   GtkAllocation child;
2302   GtkRequisition req;
2303   gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2304
2305   widget->allocation = *allocation;
2306
2307   gtk_widget_style_get (GTK_WIDGET (widget),
2308                         "focus-line-width", &focus_width,
2309                         "focus-padding", &focus_pad,
2310                         NULL);
2311
2312   if (GTK_SHADOW_NONE != priv->shadow_type)
2313     {
2314       shadow_width = widget->style->xthickness;
2315       shadow_height = widget->style->ythickness;
2316     }
2317   else
2318     {
2319       shadow_width = 0;
2320       shadow_height = 0;
2321     }
2322
2323   if (!priv->tree_view)
2324     {
2325       if (priv->cell_view)
2326         {
2327           gint border_width, xthickness, ythickness;
2328           gint width;
2329
2330           /* menu mode */
2331           allocation->x += shadow_width;
2332           allocation->y += shadow_height;
2333           allocation->width -= 2 * shadow_width;
2334           allocation->height -= 2 * shadow_height;
2335
2336           gtk_widget_size_allocate (priv->button, allocation);
2337
2338           /* set some things ready */
2339           border_width = GTK_CONTAINER (priv->button)->border_width;
2340           xthickness = priv->button->style->xthickness;
2341           ythickness = priv->button->style->ythickness;
2342
2343           child.x = allocation->x;
2344           child.y = allocation->y;
2345           width = allocation->width;
2346           child.height = allocation->height;
2347
2348           if (!priv->is_cell_renderer)
2349             {
2350               child.x += border_width + xthickness + focus_width + focus_pad;
2351               child.y += border_width + ythickness + focus_width + focus_pad;
2352               width -= 2 * (child.x - allocation->x);
2353               child.height -= 2 * (child.y - allocation->y);
2354             }
2355
2356
2357           /* handle the children */
2358           gtk_widget_size_request (priv->arrow, &req);
2359           child.width = req.width;
2360           if (!is_rtl)
2361             child.x += width - req.width;
2362           child.width = MAX (1, child.width);
2363           child.height = MAX (1, child.height);
2364           gtk_widget_size_allocate (priv->arrow, &child);
2365           if (is_rtl)
2366             child.x += req.width;
2367           gtk_widget_size_request (priv->separator, &req);
2368           child.width = req.width;
2369           if (!is_rtl)
2370             child.x -= req.width;
2371           child.width = MAX (1, child.width);
2372           child.height = MAX (1, child.height);
2373           gtk_widget_size_allocate (priv->separator, &child);
2374
2375           if (is_rtl)
2376             {
2377               child.x += req.width;
2378               child.width = allocation->x + allocation->width 
2379                 - (border_width + xthickness + focus_width + focus_pad) 
2380                 - child.x;
2381             }
2382           else 
2383             {
2384               child.width = child.x;
2385               child.x = allocation->x 
2386                 + border_width + xthickness + focus_width + focus_pad;
2387               child.width -= child.x;
2388             }
2389
2390           if (gtk_widget_get_visible (priv->popup_widget))
2391             {
2392               gint width;
2393               GtkRequisition requisition;
2394
2395               /* Warning here, without the check in the position func */
2396               gtk_menu_reposition (GTK_MENU (priv->popup_widget));
2397               if (priv->wrap_width == 0)
2398                 {
2399                   width = GTK_WIDGET (combo_box)->allocation.width;
2400                   gtk_widget_set_size_request (priv->popup_widget, -1, -1);
2401                   gtk_widget_size_request (priv->popup_widget, &requisition);
2402                   gtk_widget_set_size_request (priv->popup_widget,
2403                     MAX (width, requisition.width), -1);
2404                }
2405             }
2406
2407           child.width = MAX (1, child.width);
2408           child.height = MAX (1, child.height);
2409           gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
2410         }
2411       else
2412         {
2413           GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
2414
2415           if (is_rtl)
2416             child.x = allocation->x + req.width + shadow_width;
2417           else
2418             child.x = allocation->x + shadow_width;
2419           child.y = allocation->y + shadow_height;
2420           child.width = allocation->width - req.width - 2 * shadow_width;
2421           child.width = MAX (1, child.width);
2422           child.height = MAX (1, child.height);
2423           gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
2424         }
2425     }
2426   else
2427     {
2428       /* list mode */
2429
2430       /* Combobox thickness + border-width */
2431       int delta_x = shadow_width + GTK_CONTAINER (widget)->border_width;
2432       int delta_y = shadow_height + GTK_CONTAINER (widget)->border_width;
2433
2434       /* button */
2435       GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
2436
2437       /* frame */
2438       if (is_rtl)
2439         child.x = allocation->x + req.width;
2440       else
2441         child.x = allocation->x;
2442
2443       child.y = allocation->y;
2444       child.width = allocation->width - req.width;
2445       child.height = allocation->height;
2446
2447       if (priv->cell_view_frame)
2448         {
2449           child.x += delta_x;
2450           child.y += delta_y;
2451           child.width = MAX (1, child.width - delta_x * 2);
2452           child.height = MAX (1, child.height - delta_y * 2);
2453           gtk_widget_size_allocate (priv->cell_view_frame, &child);
2454
2455           /* the sample */
2456           if (priv->has_frame)
2457             {
2458               delta_x = GTK_CONTAINER (priv->cell_view_frame)->border_width +
2459                 GTK_WIDGET (priv->cell_view_frame)->style->xthickness;
2460               delta_y = GTK_CONTAINER (priv->cell_view_frame)->border_width +
2461                 GTK_WIDGET (priv->cell_view_frame)->style->ythickness;
2462
2463               child.x += delta_x;
2464               child.y += delta_y;
2465               child.width -= delta_x * 2;
2466               child.height -= delta_y * 2;
2467             }
2468         }
2469       else
2470         {
2471           child.x += delta_x;
2472           child.y += delta_y;
2473           child.width -= delta_x * 2;
2474           child.height -= delta_y * 2;
2475         }
2476
2477       if (gtk_widget_get_visible (priv->popup_window))
2478         {
2479           gint x, y, width, height;
2480           gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
2481           gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
2482           gtk_widget_set_size_request (priv->popup_window, width, height);
2483         }
2484
2485       
2486       child.width = MAX (1, child.width);
2487       child.height = MAX (1, child.height);
2488       
2489       gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
2490     }
2491 }
2492
2493 #undef GTK_COMBO_BOX_ALLOCATE_BUTTON
2494
2495 static void
2496 gtk_combo_box_unset_model (GtkComboBox *combo_box)
2497 {
2498   GtkComboBoxPrivate *priv = combo_box->priv;
2499
2500   if (priv->model)
2501     {
2502       g_signal_handler_disconnect (priv->model,
2503                                    priv->inserted_id);
2504       g_signal_handler_disconnect (priv->model,
2505                                    priv->deleted_id);
2506       g_signal_handler_disconnect (priv->model,
2507                                    priv->reordered_id);
2508       g_signal_handler_disconnect (priv->model,
2509                                    priv->changed_id);
2510     }
2511
2512   /* menu mode */
2513   if (!priv->tree_view)
2514     {
2515       if (priv->popup_widget)
2516         gtk_container_foreach (GTK_CONTAINER (priv->popup_widget),
2517                                (GtkCallback)gtk_widget_destroy, NULL);
2518     }
2519
2520   if (priv->model)
2521     {
2522       g_object_unref (priv->model);
2523       priv->model = NULL;
2524     }
2525
2526   if (priv->active_row)
2527     {
2528       gtk_tree_row_reference_free (priv->active_row);
2529       priv->active_row = NULL;
2530     }
2531
2532   if (priv->cell_view)
2533     gtk_cell_view_set_model (GTK_CELL_VIEW (priv->cell_view), NULL);
2534 }
2535
2536 static void
2537 gtk_combo_box_forall (GtkContainer *container,
2538                       gboolean      include_internals,
2539                       GtkCallback   callback,
2540                       gpointer      callback_data)
2541 {
2542   GtkComboBox *combo_box = GTK_COMBO_BOX (container);
2543   GtkComboBoxPrivate *priv = combo_box->priv;
2544
2545   if (include_internals)
2546     {
2547       if (priv->button)
2548         (* callback) (priv->button, callback_data);
2549       if (priv->cell_view_frame)
2550         (* callback) (priv->cell_view_frame, callback_data);
2551     }
2552
2553   if (GTK_BIN (container)->child)
2554     (* callback) (GTK_BIN (container)->child, callback_data);
2555 }
2556
2557 static void 
2558 gtk_combo_box_child_show (GtkWidget *widget,
2559                           GtkComboBox *combo_box)
2560 {
2561   GtkComboBoxPrivate *priv = combo_box->priv;
2562
2563   priv->popup_shown = TRUE;
2564   g_object_notify (G_OBJECT (combo_box), "popup-shown");
2565 }
2566
2567 static void 
2568 gtk_combo_box_child_hide (GtkWidget *widget,
2569                           GtkComboBox *combo_box)
2570 {
2571   GtkComboBoxPrivate *priv = combo_box->priv;
2572
2573   priv->popup_shown = FALSE;
2574   g_object_notify (G_OBJECT (combo_box), "popup-shown");
2575 }
2576
2577 static gboolean
2578 gtk_combo_box_expose_event (GtkWidget      *widget,
2579                             GdkEventExpose *event)
2580 {
2581   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
2582   GtkComboBoxPrivate *priv = combo_box->priv;
2583
2584   if (gtk_widget_is_drawable (widget) &&
2585       GTK_SHADOW_NONE != priv->shadow_type)
2586     {
2587       gtk_paint_shadow (widget->style, widget->window,
2588                         GTK_STATE_NORMAL, priv->shadow_type,
2589                         NULL, widget, "combobox",
2590                         widget->allocation.x, widget->allocation.y,
2591                         widget->allocation.width, widget->allocation.height);
2592     }
2593
2594   gtk_container_propagate_expose (GTK_CONTAINER (widget),
2595                                   priv->button, event);
2596
2597   if (priv->tree_view && priv->cell_view_frame)
2598     {
2599       gtk_container_propagate_expose (GTK_CONTAINER (widget),
2600                                       priv->cell_view_frame, event);
2601     }
2602
2603   gtk_container_propagate_expose (GTK_CONTAINER (widget),
2604                                   GTK_BIN (widget)->child, event);
2605
2606   return FALSE;
2607 }
2608
2609 typedef struct {
2610   GtkComboBox *combo;
2611   GtkTreePath *path;
2612   GtkTreeIter iter;
2613   gboolean found;
2614   gboolean set;
2615   gboolean visible;
2616 } SearchData;
2617
2618 static gboolean
2619 path_visible (GtkTreeView *view,
2620               GtkTreePath *path)
2621 {
2622   GtkRBTree *tree;
2623   GtkRBNode *node;
2624   
2625   /* Note that we rely on the fact that collapsed rows don't have nodes 
2626    */
2627   return _gtk_tree_view_find_node (view, path, &tree, &node);
2628 }
2629
2630 static gboolean
2631 tree_next_func (GtkTreeModel *model,
2632                 GtkTreePath  *path,
2633                 GtkTreeIter  *iter,
2634                 gpointer      data)
2635 {
2636   SearchData *search_data = (SearchData *)data;
2637
2638   if (search_data->found) 
2639     {
2640       if (!tree_column_row_is_sensitive (search_data->combo, iter))
2641         return FALSE;
2642       
2643       if (search_data->visible &&
2644           !path_visible (GTK_TREE_VIEW (search_data->combo->priv->tree_view), path))
2645         return FALSE;
2646
2647       search_data->set = TRUE;
2648       search_data->iter = *iter;
2649
2650       return TRUE;
2651     }
2652  
2653   if (gtk_tree_path_compare (path, search_data->path) == 0)
2654     search_data->found = TRUE;
2655   
2656   return FALSE;
2657 }
2658
2659 static gboolean
2660 tree_next (GtkComboBox  *combo,
2661            GtkTreeModel *model,
2662            GtkTreeIter  *iter,
2663            GtkTreeIter  *next,
2664            gboolean      visible)
2665 {
2666   SearchData search_data;
2667
2668   search_data.combo = combo;
2669   search_data.path = gtk_tree_model_get_path (model, iter);
2670   search_data.visible = visible;
2671   search_data.found = FALSE;
2672   search_data.set = FALSE;
2673
2674   gtk_tree_model_foreach (model, tree_next_func, &search_data);
2675   
2676   *next = search_data.iter;
2677
2678   gtk_tree_path_free (search_data.path);
2679
2680   return search_data.set;
2681 }
2682
2683 static gboolean
2684 tree_prev_func (GtkTreeModel *model,
2685                 GtkTreePath  *path,
2686                 GtkTreeIter  *iter,
2687                 gpointer      data)
2688 {
2689   SearchData *search_data = (SearchData *)data;
2690
2691   if (gtk_tree_path_compare (path, search_data->path) == 0)
2692     {
2693       search_data->found = TRUE;
2694       return TRUE;
2695     }
2696   
2697   if (!tree_column_row_is_sensitive (search_data->combo, iter))
2698     return FALSE;
2699       
2700   if (search_data->visible &&
2701       !path_visible (GTK_TREE_VIEW (search_data->combo->priv->tree_view), path))
2702     return FALSE; 
2703   
2704   search_data->set = TRUE;
2705   search_data->iter = *iter;
2706   
2707   return FALSE; 
2708 }
2709
2710 static gboolean
2711 tree_prev (GtkComboBox  *combo,
2712            GtkTreeModel *model,
2713            GtkTreeIter  *iter,
2714            GtkTreeIter  *prev,
2715            gboolean      visible)
2716 {
2717   SearchData search_data;
2718
2719   search_data.combo = combo;
2720   search_data.path = gtk_tree_model_get_path (model, iter);
2721   search_data.visible = visible;
2722   search_data.found = FALSE;
2723   search_data.set = FALSE;
2724
2725   gtk_tree_model_foreach (model, tree_prev_func, &search_data);
2726   
2727   *prev = search_data.iter;
2728
2729   gtk_tree_path_free (search_data.path);
2730
2731   return search_data.set;
2732 }
2733
2734 static gboolean
2735 tree_last_func (GtkTreeModel *model,
2736                 GtkTreePath  *path,
2737                 GtkTreeIter  *iter,
2738                 gpointer      data)
2739 {
2740   SearchData *search_data = (SearchData *)data;
2741
2742   if (!tree_column_row_is_sensitive (search_data->combo, iter))
2743     return FALSE;
2744       
2745   /* Note that we rely on the fact that collapsed rows don't have nodes 
2746    */
2747   if (search_data->visible &&
2748       !path_visible (GTK_TREE_VIEW (search_data->combo->priv->tree_view), path))
2749     return FALSE; 
2750   
2751   search_data->set = TRUE;
2752   search_data->iter = *iter;
2753   
2754   return FALSE; 
2755 }
2756
2757 static gboolean
2758 tree_last (GtkComboBox  *combo,
2759            GtkTreeModel *model,
2760            GtkTreeIter  *last,
2761            gboolean      visible)
2762 {
2763   SearchData search_data;
2764
2765   search_data.combo = combo;
2766   search_data.visible = visible;
2767   search_data.set = FALSE;
2768
2769   gtk_tree_model_foreach (model, tree_last_func, &search_data);
2770   
2771   *last = search_data.iter;
2772
2773   return search_data.set;  
2774 }
2775
2776
2777 static gboolean
2778 tree_first_func (GtkTreeModel *model,
2779                  GtkTreePath  *path,
2780                  GtkTreeIter  *iter,
2781                  gpointer      data)
2782 {
2783   SearchData *search_data = (SearchData *)data;
2784
2785   if (!tree_column_row_is_sensitive (search_data->combo, iter))
2786     return FALSE;
2787   
2788   if (search_data->visible &&
2789       !path_visible (GTK_TREE_VIEW (search_data->combo->priv->tree_view), path))
2790     return FALSE;
2791   
2792   search_data->set = TRUE;
2793   search_data->iter = *iter;
2794   
2795   return TRUE;
2796 }
2797
2798 static gboolean
2799 tree_first (GtkComboBox  *combo,
2800             GtkTreeModel *model,
2801             GtkTreeIter  *first,
2802             gboolean      visible)
2803 {
2804   SearchData search_data;
2805   
2806   search_data.combo = combo;
2807   search_data.visible = visible;
2808   search_data.set = FALSE;
2809
2810   gtk_tree_model_foreach (model, tree_first_func, &search_data);
2811   
2812   *first = search_data.iter;
2813
2814   return search_data.set;  
2815 }
2816
2817 static gboolean
2818 gtk_combo_box_scroll_event (GtkWidget          *widget,
2819                             GdkEventScroll     *event)
2820 {
2821   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
2822   gboolean found;
2823   GtkTreeIter iter;
2824   GtkTreeIter new_iter;
2825
2826   if (!gtk_combo_box_get_active_iter (combo_box, &iter))
2827     return TRUE;
2828   
2829   if (event->direction == GDK_SCROLL_UP)
2830     found = tree_prev (combo_box, combo_box->priv->model, 
2831                        &iter, &new_iter, FALSE);
2832   else
2833     found = tree_next (combo_box, combo_box->priv->model, 
2834                        &iter, &new_iter, FALSE);
2835   
2836   if (found)
2837     gtk_combo_box_set_active_iter (combo_box, &new_iter);
2838
2839   return TRUE;
2840 }
2841
2842 /*
2843  * menu style
2844  */
2845
2846 static void
2847 gtk_combo_box_sync_cells (GtkComboBox   *combo_box,
2848                           GtkCellLayout *cell_layout)
2849 {
2850   GtkComboBoxPrivate *priv = combo_box->priv;
2851   GSList *k;
2852
2853   for (k = priv->cells; k; k = k->next)
2854     {
2855       GSList *j;
2856       ComboCellInfo *info = (ComboCellInfo *)k->data;
2857
2858       if (info->pack == GTK_PACK_START)
2859         gtk_cell_layout_pack_start (cell_layout,
2860                                     info->cell, info->expand);
2861       else if (info->pack == GTK_PACK_END)
2862         gtk_cell_layout_pack_end (cell_layout,
2863                                   info->cell, info->expand);
2864
2865       gtk_cell_layout_set_cell_data_func (cell_layout,
2866                                           info->cell,
2867                                           combo_cell_data_func, info, NULL);
2868
2869       for (j = info->attributes; j; j = j->next->next)
2870         {
2871           gtk_cell_layout_add_attribute (cell_layout,
2872                                          info->cell,
2873                                          j->data,
2874                                          GPOINTER_TO_INT (j->next->data));
2875         }
2876     }
2877 }
2878
2879 static void
2880 gtk_combo_box_menu_setup (GtkComboBox *combo_box,
2881                           gboolean     add_children)
2882 {
2883   GtkComboBoxPrivate *priv = combo_box->priv;
2884   GtkWidget *menu;
2885
2886   if (priv->cell_view)
2887     {
2888       priv->button = gtk_toggle_button_new ();
2889       gtk_button_set_focus_on_click (GTK_BUTTON (priv->button),
2890                                      priv->focus_on_click);
2891
2892       g_signal_connect (priv->button, "toggled",
2893                         G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
2894       gtk_widget_set_parent (priv->button,
2895                              GTK_BIN (combo_box)->child->parent);
2896
2897       priv->box = gtk_hbox_new (FALSE, 0);
2898       gtk_container_add (GTK_CONTAINER (priv->button), priv->box);
2899
2900       priv->separator = gtk_vseparator_new ();
2901       gtk_container_add (GTK_CONTAINER (priv->box), priv->separator);
2902
2903       priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2904       gtk_container_add (GTK_CONTAINER (priv->box), priv->arrow);
2905
2906       gtk_widget_show_all (priv->button);
2907     }
2908   else
2909     {
2910       priv->button = gtk_toggle_button_new ();
2911       gtk_button_set_focus_on_click (GTK_BUTTON (priv->button),
2912                                      priv->focus_on_click);
2913
2914       g_signal_connect (priv->button, "toggled",
2915                         G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
2916       gtk_widget_set_parent (priv->button,
2917                              GTK_BIN (combo_box)->child->parent);
2918
2919       priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2920       gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow);
2921       gtk_widget_show_all (priv->button);
2922     }
2923
2924   g_signal_connect (priv->button, "button-press-event",
2925                     G_CALLBACK (gtk_combo_box_menu_button_press),
2926                     combo_box);
2927   g_signal_connect (priv->button, "state-changed",
2928                     G_CALLBACK (gtk_combo_box_button_state_changed), 
2929                     combo_box);
2930
2931   /* create our funky menu */
2932   menu = gtk_menu_new ();
2933   gtk_widget_set_name (menu, "gtk-combobox-popup-menu");
2934   gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
2935   
2936   g_signal_connect (menu, "key-press-event",
2937                     G_CALLBACK (gtk_combo_box_menu_key_press), combo_box);
2938   gtk_combo_box_set_popup_widget (combo_box, menu);
2939
2940   /* add items */
2941   if (add_children)
2942     gtk_combo_box_menu_fill (combo_box);
2943
2944   /* the column is needed in tree_column_row_is_sensitive() */
2945   priv->column = gtk_tree_view_column_new ();
2946   g_object_ref_sink (priv->column);
2947   gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (priv->column));
2948
2949   gtk_combo_box_update_title (combo_box);
2950   gtk_combo_box_update_sensitivity (combo_box);
2951 }
2952
2953 static void
2954 gtk_combo_box_menu_fill (GtkComboBox *combo_box)
2955 {
2956   GtkComboBoxPrivate *priv = combo_box->priv;
2957   GtkWidget *menu;
2958
2959   if (!priv->model)
2960     return;
2961
2962   menu = priv->popup_widget;
2963
2964   if (priv->add_tearoffs)
2965     {
2966       GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
2967
2968       gtk_widget_show (tearoff);
2969       
2970       if (priv->wrap_width)
2971         gtk_menu_attach (GTK_MENU (menu), tearoff, 0, priv->wrap_width, 0, 1);
2972       else
2973         gtk_menu_shell_append (GTK_MENU_SHELL (menu), tearoff);
2974     }
2975   
2976   gtk_combo_box_menu_fill_level (combo_box, menu, NULL);
2977 }
2978
2979 static GtkWidget *
2980 gtk_cell_view_menu_item_new (GtkComboBox  *combo_box,
2981                              GtkTreeModel *model,
2982                              GtkTreeIter  *iter)
2983 {
2984   GtkWidget *cell_view; 
2985   GtkWidget *item;
2986   GtkTreePath *path;
2987   GtkRequisition req;
2988
2989   cell_view = gtk_cell_view_new ();
2990   item = gtk_menu_item_new ();
2991   gtk_container_add (GTK_CONTAINER (item), cell_view);
2992
2993   gtk_cell_view_set_model (GTK_CELL_VIEW (cell_view), model);     
2994   path = gtk_tree_model_get_path (model, iter);
2995   gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (cell_view), path);
2996   gtk_tree_path_free (path);
2997
2998   gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (cell_view));
2999   gtk_widget_size_request (cell_view, &req);
3000   gtk_widget_show (cell_view);
3001   
3002   return item;
3003 }
3004  
3005 static void
3006 gtk_combo_box_menu_fill_level (GtkComboBox *combo_box,
3007                                GtkWidget   *menu,
3008                                GtkTreeIter *parent)
3009 {
3010   GtkComboBoxPrivate *priv = combo_box->priv;
3011   GtkTreeModel *model = priv->model;
3012   GtkWidget *item, *submenu, *subitem, *separator;
3013   GtkTreeIter iter;
3014   gboolean is_separator;
3015   gint i, n_children;
3016   GtkWidget *last;
3017   GtkTreePath *path;
3018   
3019   n_children = gtk_tree_model_iter_n_children (model, parent);
3020   
3021   last = NULL;
3022   for (i = 0; i < n_children; i++)
3023     {
3024       gtk_tree_model_iter_nth_child (model, &iter, parent, i);
3025
3026       if (priv->row_separator_func)
3027         is_separator = priv->row_separator_func (priv->model, &iter,
3028                                                  priv->row_separator_data);
3029       else
3030         is_separator = FALSE;
3031       
3032       if (is_separator)
3033         {
3034           item = gtk_separator_menu_item_new ();
3035           path = gtk_tree_model_get_path (model, &iter);
3036           g_object_set_data_full (G_OBJECT (item),
3037                                   I_("gtk-combo-box-item-path"),
3038                                   gtk_tree_row_reference_new (model, path),
3039                                   (GDestroyNotify)gtk_tree_row_reference_free);
3040           gtk_tree_path_free (path);
3041         }
3042       else
3043         {
3044           item = gtk_cell_view_menu_item_new (combo_box, model, &iter);
3045           if (gtk_tree_model_iter_has_child (model, &iter))
3046             {
3047               submenu = gtk_menu_new ();
3048               gtk_menu_set_reserve_toggle_size (GTK_MENU (submenu), FALSE);
3049               gtk_widget_show (submenu);
3050               gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
3051               
3052               /* Ugly - since menus can only activate leafs, we have to
3053                * duplicate the item inside the submenu.
3054                */
3055               subitem = gtk_cell_view_menu_item_new (combo_box, model, &iter);
3056               separator = gtk_separator_menu_item_new ();
3057               gtk_widget_show (subitem);
3058               gtk_widget_show (separator);
3059               g_signal_connect (subitem, "activate",
3060                                 G_CALLBACK (gtk_combo_box_menu_item_activate),
3061                                 combo_box);
3062               gtk_menu_shell_append (GTK_MENU_SHELL (submenu), subitem);
3063               gtk_menu_shell_append (GTK_MENU_SHELL (submenu), separator);
3064               
3065               gtk_combo_box_menu_fill_level (combo_box, submenu, &iter);
3066             }
3067           g_signal_connect (item, "activate",
3068                             G_CALLBACK (gtk_combo_box_menu_item_activate),
3069                             combo_box);
3070         }
3071       
3072       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3073       if (priv->wrap_width && menu == priv->popup_widget)
3074         gtk_combo_box_relayout_item (combo_box, item, &iter, last);
3075       gtk_widget_show (item);
3076       
3077       last = item;
3078     }
3079 }
3080
3081 static void
3082 gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
3083 {
3084   GtkComboBoxPrivate *priv = combo_box->priv;
3085
3086   g_signal_handlers_disconnect_matched (priv->button,
3087                                         G_SIGNAL_MATCH_DATA,
3088                                         0, 0, NULL,
3089                                         gtk_combo_box_menu_button_press, NULL);
3090   g_signal_handlers_disconnect_matched (priv->button,
3091                                         G_SIGNAL_MATCH_DATA,
3092                                         0, 0, NULL,
3093                                         gtk_combo_box_button_state_changed, combo_box);
3094
3095   /* unparent will remove our latest ref */
3096   gtk_widget_unparent (priv->button);
3097   
3098   priv->box = NULL;
3099   priv->button = NULL;
3100   priv->arrow = NULL;
3101   priv->separator = NULL;
3102
3103   g_object_unref (priv->column);
3104   priv->column = NULL;
3105
3106   /* changing the popup window will unref the menu and the children */
3107 }
3108
3109 /*
3110  * grid
3111  */
3112
3113 static gboolean
3114 menu_occupied (GtkMenu   *menu,
3115                guint      left_attach,
3116                guint      right_attach,
3117                guint      top_attach,
3118                guint      bottom_attach)
3119 {
3120   GList *i;
3121
3122   for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
3123     {
3124       guint l, r, b, t;
3125
3126       gtk_container_child_get (GTK_CONTAINER (menu), 
3127                                i->data,
3128                                "left-attach", &l,
3129                                "right-attach", &r,
3130                                "bottom-attach", &b,
3131                                "top-attach", &t,
3132                                NULL);
3133
3134       /* look if this item intersects with the given coordinates */
3135       if (right_attach > l && left_attach < r && bottom_attach > t && top_attach < b)
3136         return TRUE;
3137     }
3138
3139   return FALSE;
3140 }
3141
3142 static void
3143 gtk_combo_box_relayout_item (GtkComboBox *combo_box,
3144                              GtkWidget   *item,
3145                              GtkTreeIter *iter,
3146                              GtkWidget   *last)
3147 {
3148   GtkComboBoxPrivate *priv = combo_box->priv;
3149   gint current_col = 0, current_row = 0;
3150   gint rows = 1, cols = 1;
3151   GtkWidget *menu = priv->popup_widget;
3152
3153   if (!GTK_IS_MENU_SHELL (menu))
3154     return;
3155   
3156   if (priv->col_column == -1 &&
3157       priv->row_column == -1 &&
3158       last)
3159     {
3160       gtk_container_child_get (GTK_CONTAINER (menu), 
3161                                last,
3162                                "right-attach", &current_col,
3163                                "top-attach", &current_row,
3164                                NULL);
3165       if (current_col + cols > priv->wrap_width)
3166         {
3167           current_col = 0;
3168           current_row++;
3169         }
3170     }
3171   else
3172     {
3173       if (priv->col_column != -1)
3174         gtk_tree_model_get (priv->model, iter,
3175                             priv->col_column, &cols,
3176                             -1);
3177       if (priv->row_column != -1)
3178         gtk_tree_model_get (priv->model, iter,
3179                             priv->row_column, &rows,
3180                             -1);
3181
3182       while (1)
3183         {
3184           if (current_col + cols > priv->wrap_width)
3185             {
3186               current_col = 0;
3187               current_row++;
3188             }
3189           
3190           if (!menu_occupied (GTK_MENU (menu), 
3191                               current_col, current_col + cols,
3192                               current_row, current_row + rows))
3193             break;
3194           
3195           current_col++;
3196         }
3197     }
3198
3199   /* set attach props */
3200   gtk_menu_attach (GTK_MENU (menu), item,
3201                    current_col, current_col + cols,
3202                    current_row, current_row + rows);
3203 }
3204
3205 static void
3206 gtk_combo_box_relayout (GtkComboBox *combo_box)
3207 {
3208   GList *list, *j;
3209   GtkWidget *menu;
3210
3211   menu = combo_box->priv->popup_widget;
3212   
3213   /* do nothing unless we are in menu style and realized */
3214   if (combo_box->priv->tree_view || !GTK_IS_MENU_SHELL (menu))
3215     return;
3216   
3217   list = gtk_container_get_children (GTK_CONTAINER (menu));
3218   
3219   for (j = g_list_last (list); j; j = j->prev)
3220     gtk_container_remove (GTK_CONTAINER (menu), j->data);
3221   
3222   gtk_combo_box_menu_fill (combo_box);
3223
3224   g_list_free (list);
3225 }
3226
3227 /* callbacks */
3228 static gboolean
3229 gtk_combo_box_menu_button_press (GtkWidget      *widget,
3230                                  GdkEventButton *event,
3231                                  gpointer        user_data)
3232 {
3233   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3234   GtkComboBoxPrivate *priv = combo_box->priv;
3235
3236   if (GTK_IS_MENU (priv->popup_widget) &&
3237       event->type == GDK_BUTTON_PRESS && event->button == 1)
3238     {
3239       if (priv->focus_on_click && 
3240           !gtk_widget_has_focus (priv->button))
3241         gtk_widget_grab_focus (priv->button);
3242
3243       gtk_combo_box_menu_popup (combo_box, event->button, event->time);
3244
3245       return TRUE;
3246     }
3247
3248   return FALSE;
3249 }
3250
3251 static void
3252 gtk_combo_box_menu_item_activate (GtkWidget *item,
3253                                   gpointer   user_data)
3254 {
3255   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3256   GtkWidget *cell_view;
3257   GtkTreePath *path;
3258   GtkTreeIter iter;
3259
3260   cell_view = GTK_BIN (item)->child;
3261
3262   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
3263
3264   path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (cell_view));
3265
3266   if (gtk_tree_model_get_iter (combo_box->priv->model, &iter, path))
3267   {
3268     if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)) == NULL)
3269       gtk_combo_box_set_active_iter (combo_box, &iter);
3270   }
3271
3272   gtk_tree_path_free (path);
3273
3274   g_object_set (combo_box,
3275                 "editing-canceled", FALSE,
3276                 NULL);
3277 }
3278
3279 static void
3280 gtk_combo_box_update_sensitivity (GtkComboBox *combo_box)
3281 {
3282   GtkTreeIter iter;
3283   gboolean sensitive = TRUE; /* fool code checkers */
3284
3285   if (!combo_box->priv->button)
3286     return;
3287
3288   switch (combo_box->priv->button_sensitivity)
3289     {
3290       case GTK_SENSITIVITY_ON:
3291         sensitive = TRUE;
3292         break;
3293       case GTK_SENSITIVITY_OFF:
3294         sensitive = FALSE;
3295         break;
3296       case GTK_SENSITIVITY_AUTO:
3297         sensitive = combo_box->priv->model &&
3298                     gtk_tree_model_get_iter_first (combo_box->priv->model, &iter);
3299         break;
3300       default:
3301         g_assert_not_reached ();
3302         break;
3303     }
3304
3305   gtk_widget_set_sensitive (combo_box->priv->button, sensitive);
3306
3307   /* In list-mode, we also need to update sensitivity of the event box */
3308   if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)
3309       && combo_box->priv->cell_view)
3310     gtk_widget_set_sensitive (combo_box->priv->box, sensitive);
3311 }
3312
3313 static void
3314 gtk_combo_box_model_row_inserted (GtkTreeModel     *model,
3315                                   GtkTreePath      *path,
3316                                   GtkTreeIter      *iter,
3317                                   gpointer          user_data)
3318 {
3319   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3320
3321   if (combo_box->priv->tree_view)
3322     gtk_combo_box_list_popup_resize (combo_box);
3323   else
3324     gtk_combo_box_menu_row_inserted (model, path, iter, user_data);
3325
3326   gtk_combo_box_update_sensitivity (combo_box);
3327 }
3328
3329 static void
3330 gtk_combo_box_model_row_deleted (GtkTreeModel     *model,
3331                                  GtkTreePath      *path,
3332                                  gpointer          user_data)
3333 {
3334   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3335   GtkComboBoxPrivate *priv = combo_box->priv;
3336
3337   if (!gtk_tree_row_reference_valid (priv->active_row))
3338     {
3339       if (priv->cell_view)
3340         gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv->cell_view), NULL);
3341       g_signal_emit (combo_box, combo_box_signals[CHANGED], 0);
3342     }
3343   
3344   if (priv->tree_view)
3345     gtk_combo_box_list_popup_resize (combo_box);
3346   else
3347     gtk_combo_box_menu_row_deleted (model, path, user_data);  
3348
3349   gtk_combo_box_update_sensitivity (combo_box);
3350 }
3351
3352 static void
3353 gtk_combo_box_model_rows_reordered (GtkTreeModel    *model,
3354                                     GtkTreePath     *path,
3355                                     GtkTreeIter     *iter,
3356                                     gint            *new_order,
3357                                     gpointer         user_data)
3358 {
3359   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3360
3361   gtk_tree_row_reference_reordered (G_OBJECT (user_data), path, iter, new_order);
3362
3363   if (!combo_box->priv->tree_view)
3364     gtk_combo_box_menu_rows_reordered (model, path, iter, new_order, user_data);
3365 }
3366                                                     
3367 static void
3368 gtk_combo_box_model_row_changed (GtkTreeModel     *model,
3369                                  GtkTreePath      *path,
3370                                  GtkTreeIter      *iter,
3371                                  gpointer          user_data)
3372 {
3373   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3374   GtkComboBoxPrivate *priv = combo_box->priv;
3375   GtkTreePath *active_path;
3376
3377   /* FIXME this belongs to GtkCellView */
3378   if (gtk_tree_row_reference_valid (priv->active_row))
3379     {
3380       active_path = gtk_tree_row_reference_get_path (priv->active_row);
3381       if (gtk_tree_path_compare (path, active_path) == 0 &&
3382           priv->cell_view)
3383         gtk_widget_queue_resize (GTK_WIDGET (priv->cell_view));
3384       gtk_tree_path_free (active_path);
3385     }
3386       
3387   if (priv->tree_view)
3388     gtk_combo_box_list_row_changed (model, path, iter, user_data);
3389   else
3390     gtk_combo_box_menu_row_changed (model, path, iter, user_data);
3391 }
3392
3393 static gboolean
3394 list_popup_resize_idle (gpointer user_data)
3395 {
3396   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3397   GtkComboBoxPrivate *priv = combo_box->priv;
3398   gint x, y, width, height;
3399
3400   if (priv->tree_view && gtk_widget_get_mapped (priv->popup_window))
3401     {
3402       gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
3403   
3404       gtk_widget_set_size_request (priv->popup_window, width, height);
3405       gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
3406     }
3407
3408   priv->resize_idle_id = 0;
3409
3410   return FALSE;
3411 }
3412
3413 static void
3414 gtk_combo_box_list_popup_resize (GtkComboBox *combo_box)
3415 {
3416   GtkComboBoxPrivate *priv = combo_box->priv;
3417
3418   if (!priv->resize_idle_id)
3419     priv->resize_idle_id = 
3420       gdk_threads_add_idle (list_popup_resize_idle, combo_box);
3421 }
3422
3423 static void
3424 gtk_combo_box_model_row_expanded (GtkTreeModel     *model,
3425                                   GtkTreePath      *path,
3426                                   GtkTreeIter      *iter,
3427                                   gpointer          user_data)
3428 {
3429   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3430   
3431   gtk_combo_box_list_popup_resize (combo_box);
3432 }
3433
3434
3435 static GtkWidget *
3436 find_menu_by_path (GtkWidget   *menu,
3437                    GtkTreePath *path,
3438                    gboolean     skip_first)
3439 {
3440   GList *i, *list;
3441   GtkWidget *item;
3442   GtkWidget *submenu;    
3443   GtkTreeRowReference *mref;
3444   GtkTreePath *mpath;
3445   gboolean skip;
3446
3447   list = gtk_container_get_children (GTK_CONTAINER (menu));
3448   skip = skip_first;
3449   item = NULL;
3450   for (i = list; i; i = i->next)
3451     {
3452       if (GTK_IS_SEPARATOR_MENU_ITEM (i->data))
3453         {
3454           mref = g_object_get_data (G_OBJECT (i->data), "gtk-combo-box-item-path");
3455           if (!mref)
3456             continue;
3457           else if (!gtk_tree_row_reference_valid (mref))
3458             mpath = NULL;
3459           else
3460             mpath = gtk_tree_row_reference_get_path (mref);
3461         }
3462       else if (GTK_IS_CELL_VIEW (GTK_BIN (i->data)->child))
3463         {
3464           if (skip)
3465             {
3466               skip = FALSE;
3467               continue;
3468             }
3469
3470           mpath = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (GTK_BIN (i->data)->child));
3471         }
3472       else 
3473         continue;
3474
3475       /* this case is necessary, since the row reference of
3476        * the cell view may already be updated after a deletion
3477        */
3478       if (!mpath)
3479         {
3480           item = i->data;
3481           break;
3482         }
3483       if (gtk_tree_path_compare (mpath, path) == 0)
3484         {
3485           gtk_tree_path_free (mpath);
3486           item = i->data;
3487           break;
3488         }
3489       if (gtk_tree_path_is_ancestor (mpath, path))
3490         {
3491           submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
3492           if (submenu != NULL)
3493             {
3494               gtk_tree_path_free (mpath);
3495               item = find_menu_by_path (submenu, path, TRUE);
3496               break;
3497             }
3498         }
3499       gtk_tree_path_free (mpath);
3500     }
3501   
3502   g_list_free (list);  
3503
3504   return item;
3505 }
3506
3507 #if 0
3508 static void
3509 dump_menu_tree (GtkWidget   *menu, 
3510                 gint         level)
3511 {
3512   GList *i, *list;
3513   GtkWidget *submenu;    
3514   GtkTreePath *path;
3515
3516   list = gtk_container_get_children (GTK_CONTAINER (menu));
3517   for (i = list; i; i = i->next)
3518     {
3519       if (GTK_IS_CELL_VIEW (GTK_BIN (i->data)->child))
3520         {
3521           path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (GTK_BIN (i->data)->child));
3522           g_print ("%*s%s\n", 2 * level, " ", gtk_tree_path_to_string (path));
3523           gtk_tree_path_free (path);
3524
3525           submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
3526           if (submenu != NULL)
3527             dump_menu_tree (submenu, level + 1);
3528         }
3529     }
3530   
3531   g_list_free (list);  
3532 }
3533 #endif
3534
3535 static void
3536 gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
3537                                  GtkTreePath  *path,
3538                                  GtkTreeIter  *iter,
3539                                  gpointer      user_data)
3540 {
3541   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3542   GtkComboBoxPrivate *priv = combo_box->priv;
3543   GtkWidget *parent;
3544   GtkWidget *item, *menu, *separator;
3545   GtkTreePath *ppath;
3546   GtkTreeIter piter;
3547   gint depth, pos;
3548   gboolean is_separator;
3549
3550   if (!priv->popup_widget)
3551     return;
3552
3553   depth = gtk_tree_path_get_depth (path);
3554   pos = gtk_tree_path_get_indices (path)[depth - 1];
3555   if (depth > 1)
3556     {
3557       ppath = gtk_tree_path_copy (path);
3558       gtk_tree_path_up (ppath);
3559       parent = find_menu_by_path (priv->popup_widget, ppath, FALSE);
3560       gtk_tree_path_free (ppath);
3561
3562       menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (parent));
3563       if (!menu)
3564         {
3565           menu = gtk_menu_new ();
3566           gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
3567           gtk_widget_show (menu);
3568           gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), menu);
3569           
3570           /* Ugly - since menus can only activate leaves, we have to
3571            * duplicate the item inside the submenu.
3572            */
3573           gtk_tree_model_iter_parent (model, &piter, iter);
3574           item = gtk_cell_view_menu_item_new (combo_box, model, &piter);
3575           separator = gtk_separator_menu_item_new ();
3576           g_signal_connect (item, "activate",
3577                             G_CALLBACK (gtk_combo_box_menu_item_activate),
3578                             combo_box);
3579           gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3580           gtk_menu_shell_append (GTK_MENU_SHELL (menu), separator);
3581           if (cell_view_is_sensitive (GTK_CELL_VIEW (GTK_BIN (item)->child)))
3582             {
3583               gtk_widget_show (item);
3584               gtk_widget_show (separator);
3585             }
3586         }
3587       pos += 2;
3588     }
3589   else
3590     {
3591       menu = priv->popup_widget;
3592       if (priv->add_tearoffs)
3593         pos += 1;
3594     }
3595   
3596   if (priv->row_separator_func)
3597     is_separator = priv->row_separator_func (model, iter,
3598                                              priv->row_separator_data);
3599   else
3600     is_separator = FALSE;
3601
3602   if (is_separator)
3603     {
3604       item = gtk_separator_menu_item_new ();
3605       g_object_set_data_full (G_OBJECT (item),
3606                               I_("gtk-combo-box-item-path"),
3607                               gtk_tree_row_reference_new (model, path),
3608                               (GDestroyNotify)gtk_tree_row_reference_free);
3609     }
3610   else
3611     {
3612       item = gtk_cell_view_menu_item_new (combo_box, model, iter);
3613       
3614       g_signal_connect (item, "activate",
3615                         G_CALLBACK (gtk_combo_box_menu_item_activate),
3616                         combo_box);
3617     }
3618
3619   gtk_widget_show (item);
3620   gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, pos);
3621 }
3622
3623 static void
3624 gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
3625                                 GtkTreePath  *path,
3626                                 gpointer      user_data)
3627 {
3628   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3629   GtkComboBoxPrivate *priv = combo_box->priv;
3630   GtkWidget *menu;
3631   GtkWidget *item;
3632
3633   if (!priv->popup_widget)
3634     return;
3635
3636   item = find_menu_by_path (priv->popup_widget, path, FALSE);
3637   menu = gtk_widget_get_parent (item);
3638   gtk_container_remove (GTK_CONTAINER (menu), item);
3639
3640   if (gtk_tree_path_get_depth (path) > 1)
3641     {
3642       GtkTreePath *parent_path;
3643       GtkTreeIter iter;
3644       GtkWidget *parent;
3645
3646       parent_path = gtk_tree_path_copy (path);
3647       gtk_tree_path_up (parent_path);
3648       gtk_tree_model_get_iter (model, &iter, parent_path);
3649
3650       if (!gtk_tree_model_iter_has_child (model, &iter))
3651         {
3652           parent = find_menu_by_path (priv->popup_widget, 
3653                                       parent_path, FALSE);
3654           gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), NULL);
3655         }
3656     }
3657 }
3658
3659 static void
3660 gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
3661                                     GtkTreePath      *path,
3662                                     GtkTreeIter      *iter,
3663                                     gint             *new_order,
3664                                     gpointer          user_data)
3665 {
3666   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3667
3668   gtk_combo_box_relayout (combo_box);
3669 }
3670                                     
3671 static void
3672 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
3673                                 GtkTreePath  *path,
3674                                 GtkTreeIter  *iter,
3675                                 gpointer      user_data)
3676 {
3677   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
3678   GtkComboBoxPrivate *priv = combo_box->priv;
3679   GtkWidget *item;
3680   gint width;
3681   gboolean is_separator;
3682
3683   if (!priv->popup_widget)
3684     return;
3685
3686   item = find_menu_by_path (priv->popup_widget, path, FALSE);
3687
3688   if (priv->row_separator_func)
3689     is_separator = priv->row_separator_func (model, iter,
3690                                              priv->row_separator_data);
3691   else
3692     is_separator = FALSE;
3693
3694   if (is_separator != GTK_IS_SEPARATOR_MENU_ITEM (item))
3695     {
3696       gtk_combo_box_menu_row_deleted (model, path, combo_box);
3697       gtk_combo_box_menu_row_inserted (model, path, iter, combo_box);
3698     }
3699
3700   if (priv->wrap_width && item->parent == priv->popup_widget)
3701     {
3702       GtkWidget *pitem = NULL;
3703       GtkTreePath *prev;
3704
3705       prev = gtk_tree_path_copy (path);
3706
3707       if (gtk_tree_path_prev (prev))
3708         pitem = find_menu_by_path (priv->popup_widget, prev, FALSE);
3709
3710       gtk_tree_path_free (prev);
3711
3712       /* unattach item so gtk_combo_box_relayout_item() won't spuriously
3713          move it */
3714       gtk_container_child_set (GTK_CONTAINER (priv->popup_widget),
3715                                item, 
3716                                "left-attach", -1, 
3717                                "right-attach", -1,
3718                                "top-attach", -1, 
3719                                "bottom-attach", -1, 
3720                                NULL);
3721
3722       gtk_combo_box_relayout_item (combo_box, item, iter, pitem);
3723     }
3724
3725   width = gtk_combo_box_calc_requested_width (combo_box, path);
3726
3727   if (width > priv->width)
3728     {
3729       if (priv->cell_view)
3730         {
3731           gtk_widget_set_size_request (priv->cell_view, width, -1);
3732           gtk_widget_queue_resize (priv->cell_view);
3733         }
3734       priv->width = width;
3735     }
3736 }
3737
3738 /*
3739  * list style
3740  */
3741
3742 static void
3743 gtk_combo_box_list_setup (GtkComboBox *combo_box)
3744 {
3745   GtkComboBoxPrivate *priv = combo_box->priv;
3746   GtkTreeSelection *sel;
3747   GtkStyle *style;
3748   GtkWidget *widget = GTK_WIDGET (combo_box);
3749
3750   priv->button = gtk_toggle_button_new ();
3751   gtk_widget_set_parent (priv->button,
3752                          GTK_BIN (combo_box)->child->parent);
3753   g_signal_connect (priv->button, "button-press-event",
3754                     G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
3755   g_signal_connect (priv->button, "toggled",
3756                     G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
3757
3758   priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
3759   gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow);
3760   priv->separator = NULL;
3761   gtk_widget_show_all (priv->button);
3762
3763   if (priv->cell_view)
3764     {
3765       style = gtk_widget_get_style (widget);
3766       gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view),
3767                                           &style->base[gtk_widget_get_state (widget)]);
3768
3769       priv->box = gtk_event_box_new ();
3770       gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->box), 
3771                                         FALSE);
3772
3773       if (priv->has_frame)
3774         {
3775           priv->cell_view_frame = gtk_frame_new (NULL);
3776           gtk_frame_set_shadow_type (GTK_FRAME (priv->cell_view_frame),
3777                                      GTK_SHADOW_IN);
3778         }
3779       else 
3780         {
3781           combo_box->priv->cell_view_frame = gtk_event_box_new ();
3782           gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->cell_view_frame), 
3783                                             FALSE);
3784         }
3785       
3786       gtk_widget_set_parent (priv->cell_view_frame,
3787                              GTK_BIN (combo_box)->child->parent);
3788       gtk_container_add (GTK_CONTAINER (priv->cell_view_frame), priv->box);
3789       gtk_widget_show_all (priv->cell_view_frame);
3790
3791       g_signal_connect (priv->box, "button-press-event",
3792                         G_CALLBACK (gtk_combo_box_list_button_pressed), 
3793                         combo_box);
3794     }
3795
3796   priv->tree_view = gtk_tree_view_new ();
3797   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
3798   gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
3799   gtk_tree_selection_set_select_function (sel,
3800                                           gtk_combo_box_list_select_func,
3801                                           NULL, NULL);
3802   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view),
3803                                      FALSE);
3804   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->tree_view),
3805                                      TRUE);
3806   if (priv->row_separator_func)
3807     gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (priv->tree_view), 
3808                                           priv->row_separator_func, 
3809                                           priv->row_separator_data, 
3810                                           NULL);
3811   if (priv->model)
3812     gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), priv->model);
3813     
3814   priv->column = gtk_tree_view_column_new ();
3815   gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), priv->column);
3816
3817   /* sync up */
3818   gtk_combo_box_sync_cells (combo_box, 
3819                             GTK_CELL_LAYOUT (priv->column));
3820
3821   if (gtk_tree_row_reference_valid (priv->active_row))
3822     {
3823       GtkTreePath *path;
3824
3825       path = gtk_tree_row_reference_get_path (priv->active_row);
3826       gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->tree_view),
3827                                 path, NULL, FALSE);
3828       gtk_tree_path_free (path);
3829     }
3830
3831   /* set sample/popup widgets */
3832   gtk_combo_box_set_popup_widget (combo_box, priv->tree_view);
3833
3834   g_signal_connect (priv->tree_view, "key-press-event",
3835                     G_CALLBACK (gtk_combo_box_list_key_press),
3836                     combo_box);
3837   g_signal_connect (priv->tree_view, "enter-notify-event",
3838                     G_CALLBACK (gtk_combo_box_list_enter_notify),
3839                     combo_box);
3840   g_signal_connect (priv->tree_view, "row-expanded",
3841                     G_CALLBACK (gtk_combo_box_model_row_expanded),
3842                     combo_box);
3843   g_signal_connect (priv->tree_view, "row-collapsed",
3844                     G_CALLBACK (gtk_combo_box_model_row_expanded),
3845                     combo_box);
3846   g_signal_connect (priv->popup_window, "button-press-event",
3847                     G_CALLBACK (gtk_combo_box_list_button_pressed),
3848                     combo_box);
3849   g_signal_connect (priv->popup_window, "button-release-event",
3850                     G_CALLBACK (gtk_combo_box_list_button_released),
3851                     combo_box);
3852
3853   gtk_widget_show (priv->tree_view);
3854
3855   gtk_combo_box_update_sensitivity (combo_box);
3856 }
3857
3858 static void
3859 gtk_combo_box_list_destroy (GtkComboBox *combo_box)
3860 {
3861   GtkComboBoxPrivate *priv = combo_box->priv;
3862
3863   /* disconnect signals */
3864   g_signal_handlers_disconnect_matched (priv->tree_view,
3865                                         G_SIGNAL_MATCH_DATA,
3866                                         0, 0, NULL, NULL, combo_box);
3867   g_signal_handlers_disconnect_matched (priv->button,
3868                                         G_SIGNAL_MATCH_DATA,
3869                                         0, 0, NULL,
3870                                         gtk_combo_box_list_button_pressed,
3871                                         NULL);
3872   g_signal_handlers_disconnect_matched (priv->popup_window,
3873                                         G_SIGNAL_MATCH_DATA,
3874                                         0, 0, NULL,
3875                                         gtk_combo_box_list_button_pressed,
3876                                         NULL);
3877   g_signal_handlers_disconnect_matched (priv->popup_window,
3878                                         G_SIGNAL_MATCH_DATA,
3879                                         0, 0, NULL,
3880                                         gtk_combo_box_list_button_released,
3881                                         NULL);
3882
3883   g_signal_handlers_disconnect_matched (priv->popup_window,
3884                                         G_SIGNAL_MATCH_DATA,
3885                                         0, 0, NULL, 
3886                                         gtk_combo_box_child_show,
3887                                         NULL);
3888
3889   g_signal_handlers_disconnect_matched (priv->popup_window,
3890                                         G_SIGNAL_MATCH_DATA,
3891                                         0, 0, NULL, 
3892                                         gtk_combo_box_child_hide,
3893                                         NULL);
3894   
3895   if (priv->box)
3896     g_signal_handlers_disconnect_matched (priv->box,
3897                                           G_SIGNAL_MATCH_DATA,
3898                                           0, 0, NULL,
3899                                           gtk_combo_box_list_button_pressed,
3900                                           NULL);
3901
3902   /* destroy things (unparent will kill the latest ref from us)
3903    * last unref on button will destroy the arrow
3904    */
3905   gtk_widget_unparent (priv->button);
3906   priv->button = NULL;
3907   priv->arrow = NULL;
3908
3909   if (priv->cell_view)
3910     {
3911       g_object_set (priv->cell_view,
3912                     "background-set", FALSE,
3913                     NULL);
3914     }
3915
3916   if (priv->cell_view_frame)
3917     {
3918       gtk_widget_unparent (priv->cell_view_frame);
3919       priv->cell_view_frame = NULL;
3920       priv->box = NULL;
3921     }
3922
3923   if (priv->scroll_timer)
3924     {
3925       g_source_remove (priv->scroll_timer);
3926       priv->scroll_timer = 0;
3927     }
3928
3929   if (priv->resize_idle_id)
3930     {
3931       g_source_remove (priv->resize_idle_id);
3932       priv->resize_idle_id = 0;
3933     }
3934
3935   gtk_widget_destroy (priv->tree_view);
3936
3937   priv->tree_view = NULL;
3938   if (priv->popup_widget)
3939     {
3940       g_object_unref (priv->popup_widget);
3941       priv->popup_widget = NULL;
3942     }
3943 }
3944
3945 /* callbacks */
3946
3947 static gboolean
3948 gtk_combo_box_list_button_pressed (GtkWidget      *widget,
3949                                    GdkEventButton *event,
3950                                    gpointer        data)
3951 {
3952   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
3953   GtkComboBoxPrivate *priv = combo_box->priv;
3954
3955   GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
3956
3957   if (ewidget == priv->popup_window)
3958     return TRUE;
3959
3960   if ((ewidget != priv->button && ewidget != priv->box) ||
3961       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)))
3962     return FALSE;
3963
3964   if (priv->focus_on_click && 
3965       !gtk_widget_has_focus (priv->button))
3966     gtk_widget_grab_focus (priv->button);
3967
3968   gtk_combo_box_popup_for_device (combo_box, event->device);
3969
3970   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE);
3971
3972   priv->auto_scroll = FALSE;
3973   if (priv->scroll_timer == 0)
3974     priv->scroll_timer = gdk_threads_add_timeout (SCROLL_TIME, 
3975                                                   (GSourceFunc) gtk_combo_box_list_scroll_timeout, 
3976                                                    combo_box);
3977
3978   priv->popup_in_progress = TRUE;
3979
3980   return TRUE;
3981 }
3982
3983 static gboolean
3984 gtk_combo_box_list_button_released (GtkWidget      *widget,
3985                                     GdkEventButton *event,
3986                                     gpointer        data)
3987 {
3988   gboolean ret;
3989   GtkTreePath *path = NULL;
3990   GtkTreeIter iter;
3991
3992   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
3993   GtkComboBoxPrivate *priv = combo_box->priv;
3994
3995   gboolean popup_in_progress = FALSE;
3996
3997   GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
3998
3999   if (priv->popup_in_progress)
4000     {
4001       popup_in_progress = TRUE;
4002       priv->popup_in_progress = FALSE;
4003     }
4004
4005   gtk_tree_view_set_hover_expand (GTK_TREE_VIEW (priv->tree_view), 
4006                                   FALSE);
4007   if (priv->scroll_timer)
4008     {
4009       g_source_remove (priv->scroll_timer);
4010       priv->scroll_timer = 0;
4011     }
4012
4013   if (ewidget != priv->tree_view)
4014     {
4015       if ((ewidget == priv->button || 
4016            ewidget == priv->box) &&
4017           !popup_in_progress &&
4018           gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)))
4019         {
4020           gtk_combo_box_popdown (combo_box);
4021           return TRUE;
4022         }
4023
4024       /* released outside treeview */
4025       if (ewidget != priv->button && ewidget != priv->box)
4026         {
4027           gtk_combo_box_popdown (combo_box);
4028
4029           return TRUE;
4030         }
4031
4032       return FALSE;
4033     }
4034
4035   /* select something cool */
4036   ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->tree_view),
4037                                        event->x, event->y,
4038                                        &path,
4039                                        NULL, NULL, NULL);
4040
4041   if (!ret)
4042     return TRUE; /* clicked outside window? */
4043
4044   gtk_tree_model_get_iter (priv->model, &iter, path);
4045   gtk_tree_path_free (path);
4046
4047   gtk_combo_box_popdown (combo_box);
4048
4049   if (tree_column_row_is_sensitive (combo_box, &iter))
4050     gtk_combo_box_set_active_iter (combo_box, &iter);
4051
4052   return TRUE;
4053 }
4054
4055 static gboolean
4056 gtk_combo_box_menu_key_press (GtkWidget   *widget,
4057                               GdkEventKey *event,
4058                               gpointer     data)
4059 {
4060   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
4061
4062   if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event))
4063     {
4064       /* The menu hasn't managed the
4065        * event, forward it to the combobox
4066        */
4067       gtk_bindings_activate_event (GTK_OBJECT (combo_box), event);
4068     }
4069
4070   return TRUE;
4071 }
4072
4073 static gboolean
4074 gtk_combo_box_list_key_press (GtkWidget   *widget,
4075                               GdkEventKey *event,
4076                               gpointer     data)
4077 {
4078   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
4079   GtkTreeIter iter;
4080
4081   if (event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter || event->keyval == GDK_KP_Enter ||
4082       event->keyval == GDK_space || event->keyval == GDK_KP_Space) 
4083   {
4084     GtkTreeModel *model = NULL;
4085     
4086     gtk_combo_box_popdown (combo_box);
4087     
4088     if (combo_box->priv->model)
4089       {
4090         GtkTreeSelection *sel;
4091
4092         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
4093
4094         if (gtk_tree_selection_get_selected (sel, &model, &iter))
4095           gtk_combo_box_set_active_iter (combo_box, &iter);
4096       }
4097     
4098     return TRUE;
4099   }
4100
4101   if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event))
4102     {
4103       /* The list hasn't managed the
4104        * event, forward it to the combobox
4105        */
4106       gtk_bindings_activate_event (GTK_OBJECT (combo_box), event);
4107     }
4108
4109   return TRUE;
4110 }
4111
4112 static void
4113 gtk_combo_box_list_auto_scroll (GtkComboBox *combo_box,
4114                                 gint         x, 
4115                                 gint         y)
4116 {
4117   GtkWidget *tree_view = combo_box->priv->tree_view;
4118   GtkAdjustment *adj;
4119   gdouble value;
4120
4121   adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window));
4122   if (adj && adj->upper - adj->lower > adj->page_size)
4123     {
4124       if (x <= tree_view->allocation.x && 
4125           adj->lower < adj->value)
4126         {
4127           value = adj->value - (tree_view->allocation.x - x + 1);
4128           gtk_adjustment_set_value (adj, value);
4129         }
4130       else if (x >= tree_view->allocation.x + tree_view->allocation.width &&
4131                adj->upper - adj->page_size > adj->value)
4132         {
4133           value = adj->value + (x - tree_view->allocation.x - tree_view->allocation.width + 1);
4134           gtk_adjustment_set_value (adj, MAX (value, 0.0));
4135         }
4136     }
4137
4138   adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window));
4139   if (adj && adj->upper - adj->lower > adj->page_size)
4140     {
4141       if (y <= tree_view->allocation.y && 
4142           adj->lower < adj->value)
4143         {
4144           value = adj->value - (tree_view->allocation.y - y + 1);
4145           gtk_adjustment_set_value (adj, value);
4146         }
4147       else if (y >= tree_view->allocation.height &&
4148                adj->upper - adj->page_size > adj->value)
4149         {
4150           value = adj->value + (y - tree_view->allocation.height + 1);
4151           gtk_adjustment_set_value (adj, MAX (value, 0.0));
4152         }
4153     }
4154 }
4155
4156 static gboolean
4157 gtk_combo_box_list_scroll_timeout (GtkComboBox *combo_box)
4158 {
4159   GtkComboBoxPrivate *priv = combo_box->priv;
4160   gint x, y;
4161
4162   if (priv->auto_scroll)
4163     {
4164       gdk_window_get_device_position (priv->tree_view->window,
4165                                       priv->grab_pointer,
4166                                       &x, &y, NULL);
4167       gtk_combo_box_list_auto_scroll (combo_box, x, y);
4168     }
4169
4170   return TRUE;
4171 }
4172
4173 static gboolean 
4174 gtk_combo_box_list_enter_notify (GtkWidget        *widget,
4175                                  GdkEventCrossing *event,
4176                                  gpointer          data)
4177 {
4178   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
4179
4180   combo_box->priv->auto_scroll = TRUE;
4181
4182   return TRUE;
4183 }
4184
4185 static gboolean
4186 gtk_combo_box_list_select_func (GtkTreeSelection *selection,
4187                                 GtkTreeModel     *model,
4188                                 GtkTreePath      *path,
4189                                 gboolean          path_currently_selected,
4190                                 gpointer          data)
4191 {
4192   GList *list;
4193   gboolean sensitive = FALSE;
4194
4195   for (list = selection->tree_view->priv->columns; list && !sensitive; list = list->next)
4196     {
4197       GList *cells, *cell;
4198       gboolean cell_sensitive, cell_visible;
4199       GtkTreeIter iter;
4200       GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
4201
4202       if (!column->visible)
4203         continue;
4204
4205       gtk_tree_model_get_iter (model, &iter, path);
4206       gtk_tree_view_column_cell_set_cell_data (column, model, &iter,
4207                                                FALSE, FALSE);
4208
4209       cell = cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
4210       while (cell)
4211         {
4212           g_object_get (cell->data,
4213                         "sensitive", &cell_sensitive,
4214                         "visible", &cell_visible,
4215                         NULL);
4216
4217           if (cell_visible && cell_sensitive)
4218             break;
4219
4220           cell = cell->next;
4221         }
4222       g_list_free (cells);
4223
4224       sensitive = cell_sensitive;
4225     }
4226
4227   return sensitive;
4228 }
4229
4230 static void
4231 gtk_combo_box_list_row_changed (GtkTreeModel *model,
4232                                 GtkTreePath  *path,
4233                                 GtkTreeIter  *iter,
4234                                 gpointer      data)
4235 {
4236   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
4237   GtkComboBoxPrivate *priv = combo_box->priv;
4238   gint width;
4239
4240   width = gtk_combo_box_calc_requested_width (combo_box, path);
4241
4242   if (width > priv->width)
4243     {
4244       if (priv->cell_view) 
4245         {
4246           gtk_widget_set_size_request (priv->cell_view, width, -1);
4247           gtk_widget_queue_resize (priv->cell_view);
4248         }
4249       priv->width = width;
4250     }
4251 }
4252
4253 /*
4254  * GtkCellLayout implementation
4255  */
4256
4257 static void
4258 pack_start_recurse (GtkWidget       *menu,
4259                     GtkCellRenderer *cell,
4260                     gboolean         expand)
4261 {
4262   GList *i, *list;
4263   GtkWidget *submenu;    
4264   
4265   list = gtk_container_get_children (GTK_CONTAINER (menu));
4266   for (i = list; i; i = i->next)
4267     {
4268       if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child))
4269         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), 
4270                                     cell, expand);
4271
4272       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4273       if (submenu != NULL)
4274         pack_start_recurse (submenu, cell, expand);
4275     }
4276
4277   g_list_free (list);
4278 }
4279
4280 static void
4281 gtk_combo_box_cell_layout_pack_start (GtkCellLayout   *layout,
4282                                       GtkCellRenderer *cell,
4283                                       gboolean         expand)
4284 {
4285   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4286   ComboCellInfo *info;
4287   GtkComboBoxPrivate *priv;
4288
4289   priv = combo_box->priv;
4290
4291   g_object_ref_sink (cell);
4292
4293   info = g_slice_new0 (ComboCellInfo);
4294   info->cell = cell;
4295   info->expand = expand;
4296   info->pack = GTK_PACK_START;
4297
4298   priv->cells = g_slist_append (priv->cells, info);
4299
4300   if (priv->cell_view)
4301     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view),
4302                                 cell, expand);
4303
4304   if (priv->column)
4305     gtk_tree_view_column_pack_start (priv->column, cell, expand);
4306
4307   if (GTK_IS_MENU (priv->popup_widget))
4308     pack_start_recurse (priv->popup_widget, cell, expand);
4309 }
4310
4311 static void
4312 pack_end_recurse (GtkWidget       *menu,
4313                   GtkCellRenderer *cell,
4314                   gboolean         expand)
4315 {
4316   GList *i, *list;
4317   GtkWidget *submenu;    
4318   
4319   list = gtk_container_get_children (GTK_CONTAINER (menu));
4320   for (i = list; i; i = i->next)
4321     {
4322       if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child))
4323         gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), 
4324                                   cell, expand);
4325
4326       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4327       if (submenu != NULL)
4328         pack_end_recurse (submenu, cell, expand);
4329     }
4330
4331   g_list_free (list);
4332 }
4333
4334 static void
4335 gtk_combo_box_cell_layout_pack_end (GtkCellLayout   *layout,
4336                                     GtkCellRenderer *cell,
4337                                     gboolean         expand)
4338 {
4339   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4340   ComboCellInfo *info;
4341   GtkComboBoxPrivate *priv;
4342
4343   priv = combo_box->priv;
4344
4345   g_object_ref_sink (cell);
4346
4347   info = g_slice_new0 (ComboCellInfo);
4348   info->cell = cell;
4349   info->expand = expand;
4350   info->pack = GTK_PACK_END;
4351
4352   priv->cells = g_slist_append (priv->cells, info);
4353
4354   if (priv->cell_view)
4355     gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (priv->cell_view),
4356                               cell, expand);
4357
4358   if (priv->column)
4359     gtk_tree_view_column_pack_end (priv->column, cell, expand);
4360
4361   if (GTK_IS_MENU (priv->popup_widget))
4362     pack_end_recurse (priv->popup_widget, cell, expand);
4363 }
4364
4365 static GList *
4366 gtk_combo_box_cell_layout_get_cells (GtkCellLayout *layout)
4367 {
4368   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4369   GSList *list;
4370   GList *retval = NULL;
4371
4372   for (list = combo_box->priv->cells; list; list = list->next)
4373     {
4374       ComboCellInfo *info = (ComboCellInfo *)list->data;
4375
4376       retval = g_list_prepend (retval, info->cell);
4377     }
4378
4379   return g_list_reverse (retval);
4380 }
4381
4382 static void
4383 clear_recurse (GtkWidget *menu)
4384 {
4385   GList *i, *list;
4386   GtkWidget *submenu;    
4387   
4388   list = gtk_container_get_children (GTK_CONTAINER (menu));
4389   for (i = list; i; i = i->next)
4390     {
4391       if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child))
4392         gtk_cell_layout_clear (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child)); 
4393
4394       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4395       if (submenu != NULL)
4396         clear_recurse (submenu);
4397     }
4398
4399   g_list_free (list);
4400 }
4401
4402 static void
4403 gtk_combo_box_cell_layout_clear (GtkCellLayout *layout)
4404 {
4405   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4406   GtkComboBoxPrivate *priv = combo_box->priv;
4407   GSList *i;
4408   
4409   if (priv->cell_view)
4410     gtk_cell_layout_clear (GTK_CELL_LAYOUT (priv->cell_view));
4411
4412   if (priv->column)
4413     gtk_tree_view_column_clear (priv->column);
4414
4415   for (i = priv->cells; i; i = i->next)
4416     {
4417       ComboCellInfo *info = (ComboCellInfo *)i->data;
4418
4419       gtk_combo_box_cell_layout_clear_attributes (layout, info->cell);
4420       g_object_unref (info->cell);
4421       g_slice_free (ComboCellInfo, info);
4422       i->data = NULL;
4423     }
4424   g_slist_free (priv->cells);
4425   priv->cells = NULL;
4426
4427   if (GTK_IS_MENU (priv->popup_widget))
4428     clear_recurse (priv->popup_widget);
4429 }
4430
4431 static void
4432 add_attribute_recurse (GtkWidget       *menu,
4433                        GtkCellRenderer *cell,
4434                        const gchar     *attribute,
4435                        gint             column)
4436 {
4437   GList *i, *list;
4438   GtkWidget *submenu;    
4439   
4440   list = gtk_container_get_children (GTK_CONTAINER (menu));
4441   for (i = list; i; i = i->next)
4442     {
4443       if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child))
4444         gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child),
4445                                        cell, attribute, column); 
4446
4447       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4448       if (submenu != NULL)
4449         add_attribute_recurse (submenu, cell, attribute, column);
4450     }
4451
4452   g_list_free (list);
4453 }
4454                        
4455 static void
4456 gtk_combo_box_cell_layout_add_attribute (GtkCellLayout   *layout,
4457                                          GtkCellRenderer *cell,
4458                                          const gchar     *attribute,
4459                                          gint             column)
4460 {
4461   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4462   ComboCellInfo *info;
4463
4464   info = gtk_combo_box_get_cell_info (combo_box, cell);
4465   g_return_if_fail (info != NULL);
4466
4467   info->attributes = g_slist_prepend (info->attributes,
4468                                       GINT_TO_POINTER (column));
4469   info->attributes = g_slist_prepend (info->attributes,
4470                                       g_strdup (attribute));
4471
4472   if (combo_box->priv->cell_view)
4473     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
4474                                    cell, attribute, column);
4475
4476   if (combo_box->priv->column)
4477     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column),
4478                                    cell, attribute, column);
4479
4480   if (GTK_IS_MENU (combo_box->priv->popup_widget))
4481     add_attribute_recurse (combo_box->priv->popup_widget, cell, attribute, column);
4482   gtk_widget_queue_resize (GTK_WIDGET (combo_box));
4483 }
4484
4485 static void
4486 combo_cell_data_func (GtkCellLayout   *cell_layout,
4487                       GtkCellRenderer *cell,
4488                       GtkTreeModel    *tree_model,
4489                       GtkTreeIter     *iter,
4490                       gpointer         data)
4491 {
4492   ComboCellInfo *info = (ComboCellInfo *)data;
4493   GtkWidget *parent = NULL;
4494   
4495   if (!info->func)
4496     return;
4497
4498   info->func (cell_layout, cell, tree_model, iter, info->func_data);
4499
4500   if (GTK_IS_WIDGET (cell_layout))
4501     parent = gtk_widget_get_parent (GTK_WIDGET (cell_layout));
4502   
4503   if (GTK_IS_MENU_ITEM (parent) && 
4504       gtk_menu_item_get_submenu (GTK_MENU_ITEM (parent)))
4505     g_object_set (cell, "sensitive", TRUE, NULL);
4506 }
4507
4508
4509 static void 
4510 set_cell_data_func_recurse (GtkWidget       *menu,
4511                             GtkCellRenderer *cell,
4512                             ComboCellInfo   *info)
4513 {
4514   GList *i, *list;
4515   GtkWidget *submenu;    
4516   GtkWidget *cell_view;
4517   
4518  list = gtk_container_get_children (GTK_CONTAINER (menu));
4519   for (i = list; i; i = i->next)
4520     {
4521       cell_view = GTK_BIN (i->data)->child;
4522       if (GTK_IS_CELL_LAYOUT (cell_view))
4523         {
4524           /* Override sensitivity for inner nodes; we don't
4525            * want menuitems with submenus to appear insensitive 
4526            */ 
4527           gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view), 
4528                                               cell, 
4529                                               combo_cell_data_func, 
4530                                               info, NULL); 
4531           submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4532           if (submenu != NULL)
4533             set_cell_data_func_recurse (submenu, cell, info);
4534         }
4535     }
4536
4537   g_list_free (list);
4538 }
4539
4540 static void
4541 gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
4542                                               GtkCellRenderer       *cell,
4543                                               GtkCellLayoutDataFunc  func,
4544                                               gpointer               func_data,
4545                                               GDestroyNotify         destroy)
4546 {
4547   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4548   GtkComboBoxPrivate *priv = combo_box->priv;
4549   ComboCellInfo *info;
4550
4551   info = gtk_combo_box_get_cell_info (combo_box, cell);
4552   g_return_if_fail (info != NULL);
4553   
4554   if (info->destroy)
4555     {
4556       GDestroyNotify d = info->destroy;
4557
4558       info->destroy = NULL;
4559       d (info->func_data);
4560     }
4561
4562   info->func = func;
4563   info->func_data = func_data;
4564   info->destroy = destroy;
4565
4566   if (priv->cell_view)
4567     gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->cell_view), cell, func, func_data, NULL);
4568
4569   if (priv->column)
4570     gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->column), cell, func, func_data, NULL);
4571
4572   if (GTK_IS_MENU (priv->popup_widget))
4573     set_cell_data_func_recurse (priv->popup_widget, cell, info);
4574
4575   gtk_widget_queue_resize (GTK_WIDGET (combo_box));
4576 }
4577
4578 static void 
4579 clear_attributes_recurse (GtkWidget       *menu,
4580                           GtkCellRenderer *cell)
4581 {
4582   GList *i, *list;
4583   GtkWidget *submenu;    
4584   
4585   list = gtk_container_get_children (GTK_CONTAINER (menu));
4586   for (i = list; i; i = i->next)
4587     {
4588       if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child))
4589         gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child),
4590                                             cell); 
4591       
4592       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4593       if (submenu != NULL)
4594         clear_attributes_recurse (submenu, cell);
4595     }
4596
4597   g_list_free (list);
4598 }
4599
4600 static void
4601 gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout   *layout,
4602                                             GtkCellRenderer *cell)
4603 {
4604   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4605   GtkComboBoxPrivate *priv;
4606   ComboCellInfo *info;
4607   GSList *list;
4608
4609   priv = combo_box->priv;
4610
4611   info = gtk_combo_box_get_cell_info (combo_box, cell);
4612   g_return_if_fail (info != NULL);
4613
4614   list = info->attributes;
4615   while (list && list->next)
4616     {
4617       g_free (list->data);
4618       list = list->next->next;
4619     }
4620   g_slist_free (info->attributes);
4621   info->attributes = NULL;
4622
4623   if (priv->cell_view)
4624     gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (priv->cell_view), cell);
4625
4626   if (priv->column)
4627     gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (priv->column), cell);
4628
4629   if (GTK_IS_MENU (priv->popup_widget))
4630     clear_attributes_recurse (priv->popup_widget, cell);
4631
4632   gtk_widget_queue_resize (GTK_WIDGET (combo_box));
4633 }
4634
4635 static void 
4636 reorder_recurse (GtkWidget             *menu,
4637                  GtkCellRenderer       *cell,
4638                  gint                   position)
4639 {
4640   GList *i, *list;
4641   GtkWidget *submenu;    
4642   
4643   list = gtk_container_get_children (GTK_CONTAINER (menu));
4644   for (i = list; i; i = i->next)
4645     {
4646       if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child))
4647         gtk_cell_layout_reorder (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child),
4648                                  cell, position); 
4649       
4650       submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data));
4651       if (submenu != NULL)
4652         reorder_recurse (submenu, cell, position);
4653     }
4654
4655   g_list_free (list);
4656 }
4657
4658 static void
4659 gtk_combo_box_cell_layout_reorder (GtkCellLayout   *layout,
4660                                    GtkCellRenderer *cell,
4661                                    gint             position)
4662 {
4663   GtkComboBox *combo_box = GTK_COMBO_BOX (layout);
4664   GtkComboBoxPrivate *priv;
4665   ComboCellInfo *info;
4666   GSList *link;
4667
4668   priv = combo_box->priv;
4669
4670   info = gtk_combo_box_get_cell_info (combo_box, cell);
4671
4672   g_return_if_fail (info != NULL);
4673   g_return_if_fail (position >= 0);
4674
4675   link = g_slist_find (priv->cells, info);
4676
4677   g_return_if_fail (link != NULL);
4678
4679   priv->cells = g_slist_delete_link (priv->cells, link);
4680   priv->cells = g_slist_insert (priv->cells, info, position);
4681
4682   if (priv->cell_view)
4683     gtk_cell_layout_reorder (GTK_CELL_LAYOUT (priv->cell_view),
4684                              cell, position);
4685
4686   if (priv->column)
4687     gtk_cell_layout_reorder (GTK_CELL_LAYOUT (priv->column),
4688                              cell, position);
4689
4690   if (GTK_IS_MENU (priv->popup_widget))
4691     reorder_recurse (priv->popup_widget, cell, position);
4692
4693   gtk_widget_queue_draw (GTK_WIDGET (combo_box));
4694 }
4695
4696 /*
4697  * public API
4698  */
4699
4700 /**
4701  * gtk_combo_box_new:
4702  *
4703  * Creates a new empty #GtkComboBox.
4704  *
4705  * Return value: A new #GtkComboBox.
4706  *
4707  * Since: 2.4
4708  */
4709 GtkWidget *
4710 gtk_combo_box_new (void)
4711 {
4712   return g_object_new (GTK_TYPE_COMBO_BOX, NULL);
4713 }
4714
4715 /**
4716  * gtk_combo_box_new_with_model:
4717  * @model: A #GtkTreeModel.
4718  *
4719  * Creates a new #GtkComboBox with the model initialized to @model.
4720  *
4721  * Return value: A new #GtkComboBox.
4722  *
4723  * Since: 2.4
4724  */
4725 GtkWidget *
4726 gtk_combo_box_new_with_model (GtkTreeModel *model)
4727 {
4728   GtkComboBox *combo_box;
4729
4730   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
4731
4732   combo_box = g_object_new (GTK_TYPE_COMBO_BOX, "model", model, NULL);
4733
4734   return GTK_WIDGET (combo_box);
4735 }
4736
4737 /**
4738  * gtk_combo_box_get_wrap_width:
4739  * @combo_box: A #GtkComboBox
4740  *
4741  * Returns the wrap width which is used to determine the number of columns 
4742  * for the popup menu. If the wrap width is larger than 1, the combo box 
4743  * is in table mode.
4744  *
4745  * Returns: the wrap width.
4746  *
4747  * Since: 2.6
4748  */
4749 gint
4750 gtk_combo_box_get_wrap_width (GtkComboBox *combo_box)
4751 {
4752   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), -1);
4753
4754   return combo_box->priv->wrap_width;
4755 }
4756
4757 /**
4758  * gtk_combo_box_set_wrap_width:
4759  * @combo_box: A #GtkComboBox
4760  * @width: Preferred number of columns
4761  *
4762  * Sets the wrap width of @combo_box to be @width. The wrap width is basically
4763  * the preferred number of columns when you want the popup to be layed out
4764  * in a table.
4765  *
4766  * Since: 2.4
4767  */
4768 void
4769 gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
4770                               gint         width)
4771 {
4772   GtkComboBoxPrivate *priv;
4773
4774   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
4775   g_return_if_fail (width >= 0);
4776
4777   priv = combo_box->priv;
4778
4779   if (width != priv->wrap_width)
4780     {
4781       priv->wrap_width = width;
4782
4783       gtk_combo_box_check_appearance (combo_box);
4784       gtk_combo_box_relayout (combo_box);
4785       
4786       g_object_notify (G_OBJECT (combo_box), "wrap-width");
4787     }
4788 }
4789
4790 /**
4791  * gtk_combo_box_get_row_span_column:
4792  * @combo_box: A #GtkComboBox
4793  *
4794  * Returns the column with row span information for @combo_box.
4795  *
4796  * Returns: the row span column.
4797  *
4798  * Since: 2.6
4799  */
4800 gint
4801 gtk_combo_box_get_row_span_column (GtkComboBox *combo_box)
4802 {
4803   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), -1);
4804
4805   return combo_box->priv->row_column;
4806 }
4807
4808 /**
4809  * gtk_combo_box_set_row_span_column:
4810  * @combo_box: A #GtkComboBox.
4811  * @row_span: A column in the model passed during construction.
4812  *
4813  * Sets the column with row span information for @combo_box to be @row_span.
4814  * The row span column contains integers which indicate how many rows
4815  * an item should span.
4816  *
4817  * Since: 2.4
4818  */
4819 void
4820 gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
4821                                    gint         row_span)
4822 {
4823   GtkComboBoxPrivate *priv;
4824   gint col;
4825
4826   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
4827
4828   priv = combo_box->priv;
4829
4830   col = gtk_tree_model_get_n_columns (priv->model);
4831   g_return_if_fail (row_span >= -1 && row_span < col);
4832
4833   if (row_span != priv->row_column)
4834     {
4835       priv->row_column = row_span;
4836       
4837       gtk_combo_box_relayout (combo_box);
4838  
4839       g_object_notify (G_OBJECT (combo_box), "row-span-column");
4840     }
4841 }
4842
4843 /**
4844  * gtk_combo_box_get_column_span_column:
4845  * @combo_box: A #GtkComboBox
4846  *
4847  * Returns the column with column span information for @combo_box.
4848  *
4849  * Returns: the column span column.
4850  *
4851  * Since: 2.6
4852  */
4853 gint
4854 gtk_combo_box_get_column_span_column (GtkComboBox *combo_box)
4855 {
4856   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), -1);
4857
4858   return combo_box->priv->col_column;
4859 }
4860
4861 /**
4862  * gtk_combo_box_set_column_span_column:
4863  * @combo_box: A #GtkComboBox
4864  * @column_span: A column in the model passed during construction
4865  *
4866  * Sets the column with column span information for @combo_box to be
4867  * @column_span. The column span column contains integers which indicate
4868  * how many columns an item should span.
4869  *
4870  * Since: 2.4
4871  */
4872 void
4873 gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
4874                                       gint         column_span)
4875 {
4876   GtkComboBoxPrivate *priv;
4877   gint col;
4878
4879   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
4880
4881   priv = combo_box->priv;
4882
4883   col = gtk_tree_model_get_n_columns (priv->model);
4884   g_return_if_fail (column_span >= -1 && column_span < col);
4885
4886   if (column_span != priv->col_column)
4887     {
4888       priv->col_column = column_span;
4889       
4890       gtk_combo_box_relayout (combo_box);
4891
4892       g_object_notify (G_OBJECT (combo_box), "column-span-column");
4893     }
4894 }
4895
4896 /**
4897  * gtk_combo_box_get_active:
4898  * @combo_box: A #GtkComboBox
4899  *
4900  * Returns the index of the currently active item, or -1 if there's no
4901  * active item. If the model is a non-flat treemodel, and the active item 
4902  * is not an immediate child of the root of the tree, this function returns 
4903  * <literal>gtk_tree_path_get_indices (path)[0]</literal>, where 
4904  * <literal>path</literal> is the #GtkTreePath of the active item.
4905  *
4906  * Return value: An integer which is the index of the currently active item, 
4907  *     or -1 if there's no active item.
4908  *
4909  * Since: 2.4
4910  */
4911 gint
4912 gtk_combo_box_get_active (GtkComboBox *combo_box)
4913 {
4914   GtkComboBoxPrivate *priv;
4915   gint result;
4916
4917   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
4918
4919   priv = combo_box->priv;
4920
4921   if (gtk_tree_row_reference_valid (priv->active_row))
4922     {
4923       GtkTreePath *path;
4924
4925       path = gtk_tree_row_reference_get_path (priv->active_row);      
4926       result = gtk_tree_path_get_indices (path)[0];
4927       gtk_tree_path_free (path);
4928     }
4929   else
4930     result = -1;
4931
4932   return result;
4933 }
4934
4935 /**
4936  * gtk_combo_box_set_active:
4937  * @combo_box: A #GtkComboBox
4938  * @index_: An index in the model passed during construction, or -1 to have
4939  * no active item
4940  *
4941  * Sets the active item of @combo_box to be the item at @index.
4942  *
4943  * Since: 2.4
4944  */
4945 void
4946 gtk_combo_box_set_active (GtkComboBox *combo_box,
4947                           gint         index_)
4948 {
4949   GtkTreePath *path = NULL;
4950   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
4951   g_return_if_fail (index_ >= -1);
4952
4953   if (combo_box->priv->model == NULL)
4954     {
4955       /* Save index, in case the model is set after the index */
4956       combo_box->priv->active = index_;
4957       if (index_ != -1)
4958         return;
4959     }
4960
4961   if (index_ != -1)
4962     path = gtk_tree_path_new_from_indices (index_, -1);
4963    
4964   gtk_combo_box_set_active_internal (combo_box, path);
4965
4966   if (path)
4967     gtk_tree_path_free (path);
4968 }
4969
4970 static void
4971 gtk_combo_box_set_active_internal (GtkComboBox *combo_box,
4972                                    GtkTreePath *path)
4973 {
4974   GtkComboBoxPrivate *priv = combo_box->priv;
4975   GtkTreePath *active_path;
4976   gint path_cmp;
4977
4978   /* Remember whether the initially active row is valid. */
4979   gboolean is_valid_row_reference = gtk_tree_row_reference_valid (priv->active_row);
4980
4981   if (path && is_valid_row_reference)
4982     {
4983       active_path = gtk_tree_row_reference_get_path (priv->active_row);
4984       path_cmp = gtk_tree_path_compare (path, active_path);
4985       gtk_tree_path_free (active_path);
4986       if (path_cmp == 0)
4987         return;
4988     }
4989
4990   if (priv->active_row)
4991     {
4992       gtk_tree_row_reference_free (priv->active_row);
4993       priv->active_row = NULL;
4994     }
4995   
4996   if (!path)
4997     {
4998       if (priv->tree_view)
4999         gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)));
5000       else
5001         {
5002           GtkMenu *menu = GTK_MENU (priv->popup_widget);
5003
5004           if (GTK_IS_MENU (menu))
5005             gtk_menu_set_active (menu, -1);
5006         }
5007
5008       if (priv->cell_view)
5009         gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv->cell_view), NULL);
5010
5011       /*
5012        *  Do not emit a "changed" signal when an already invalid selection was
5013        *  now set to invalid.
5014        */
5015       if (!is_valid_row_reference)
5016         return;
5017     }
5018   else
5019     {
5020       priv->active_row = 
5021         gtk_tree_row_reference_new (priv->model, path);
5022
5023       if (priv->tree_view)
5024         {
5025           gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->tree_view), 
5026                                     path, NULL, FALSE);
5027         }
5028       else if (GTK_IS_MENU (priv->popup_widget))
5029         {
5030           /* FIXME handle nested menus better */
5031           gtk_menu_set_active (GTK_MENU (priv->popup_widget), 
5032                                gtk_tree_path_get_indices (path)[0]);
5033         }
5034
5035       if (priv->cell_view)
5036         gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv->cell_view), 
5037                                          path);
5038     }
5039
5040   g_signal_emit (combo_box, combo_box_signals[CHANGED], 0);
5041   g_object_notify (G_OBJECT (combo_box), "active");
5042 }
5043
5044
5045 /**
5046  * gtk_combo_box_get_active_iter:
5047  * @combo_box: A #GtkComboBox
5048  * @iter: (out): The uninitialized #GtkTreeIter
5049  * 
5050  * Sets @iter to point to the current active item, if it exists.
5051  * 
5052  * Return value: %TRUE, if @iter was set
5053  *
5054  * Since: 2.4
5055  */
5056 gboolean
5057 gtk_combo_box_get_active_iter (GtkComboBox     *combo_box,
5058                                GtkTreeIter     *iter)
5059 {
5060   GtkTreePath *path;
5061   gboolean result;
5062
5063   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
5064
5065   if (!gtk_tree_row_reference_valid (combo_box->priv->active_row))
5066     return FALSE;
5067
5068   path = gtk_tree_row_reference_get_path (combo_box->priv->active_row);
5069   result = gtk_tree_model_get_iter (combo_box->priv->model, iter, path);
5070   gtk_tree_path_free (path);
5071
5072   return result;
5073 }
5074
5075 /**
5076  * gtk_combo_box_set_active_iter:
5077  * @combo_box: A #GtkComboBox
5078  * @iter: (allow-none): The #GtkTreeIter, or %NULL
5079  * 
5080  * Sets the current active item to be the one referenced by @iter, or
5081  * unsets the active item if @iter is %NULL.
5082  *
5083  * @iter must correspond to a path of depth one, or be %NULL.
5084  * 
5085  * Since: 2.4
5086  */
5087 void
5088 gtk_combo_box_set_active_iter (GtkComboBox     *combo_box,
5089                                GtkTreeIter     *iter)
5090 {
5091   GtkTreePath *path = NULL;
5092
5093   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5094
5095   if (iter)
5096     path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
5097
5098   gtk_combo_box_set_active_internal (combo_box, path);
5099   gtk_tree_path_free (path);
5100 }
5101
5102 /**
5103  * gtk_combo_box_set_model:
5104  * @combo_box: A #GtkComboBox
5105  * @model: (allow-none): A #GtkTreeModel
5106  *
5107  * Sets the model used by @combo_box to be @model. Will unset a previously set
5108  * model (if applicable). If model is %NULL, then it will unset the model.
5109  *
5110  * Note that this function does not clear the cell renderers, you have to 
5111  * call gtk_cell_layout_clear() yourself if you need to set up different 
5112  * cell renderers for the new model.
5113  *
5114  * Since: 2.4
5115  */
5116 void
5117 gtk_combo_box_set_model (GtkComboBox  *combo_box,
5118                          GtkTreeModel *model)
5119 {
5120   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5121   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
5122
5123   if (model == combo_box->priv->model)
5124     return;
5125   
5126   gtk_combo_box_unset_model (combo_box);
5127
5128   if (model == NULL)
5129     goto out;
5130
5131   combo_box->priv->model = model;
5132   g_object_ref (combo_box->priv->model);
5133
5134   combo_box->priv->inserted_id =
5135     g_signal_connect (combo_box->priv->model, "row-inserted",
5136                       G_CALLBACK (gtk_combo_box_model_row_inserted),
5137                       combo_box);
5138   combo_box->priv->deleted_id =
5139     g_signal_connect (combo_box->priv->model, "row-deleted",
5140                       G_CALLBACK (gtk_combo_box_model_row_deleted),
5141                       combo_box);
5142   combo_box->priv->reordered_id =
5143     g_signal_connect (combo_box->priv->model, "rows-reordered",
5144                       G_CALLBACK (gtk_combo_box_model_rows_reordered),
5145                       combo_box);
5146   combo_box->priv->changed_id =
5147     g_signal_connect (combo_box->priv->model, "row-changed",
5148                       G_CALLBACK (gtk_combo_box_model_row_changed),
5149                       combo_box);
5150       
5151   if (combo_box->priv->tree_view)
5152     {
5153       /* list mode */
5154       gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
5155                                combo_box->priv->model);
5156       gtk_combo_box_list_popup_resize (combo_box);
5157     }
5158   else
5159     {
5160       /* menu mode */
5161       if (combo_box->priv->popup_widget)
5162         gtk_combo_box_menu_fill (combo_box);
5163
5164     }
5165
5166   if (combo_box->priv->cell_view)
5167     gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
5168                              combo_box->priv->model);
5169
5170   if (combo_box->priv->active != -1)
5171     {
5172       /* If an index was set in advance, apply it now */
5173       gtk_combo_box_set_active (combo_box, combo_box->priv->active);
5174       combo_box->priv->active = -1;
5175     }
5176
5177 out:
5178   gtk_combo_box_update_sensitivity (combo_box);
5179
5180   g_object_notify (G_OBJECT (combo_box), "model");
5181 }
5182
5183 /**
5184  * gtk_combo_box_get_model
5185  * @combo_box: A #GtkComboBox
5186  *
5187  * Returns the #GtkTreeModel which is acting as data source for @combo_box.
5188  *
5189  * Return value: (transfer none): A #GtkTreeModel which was passed during construction.
5190  *
5191  * Since: 2.4
5192  */
5193 GtkTreeModel *
5194 gtk_combo_box_get_model (GtkComboBox *combo_box)
5195 {
5196   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
5197
5198   return combo_box->priv->model;
5199 }
5200
5201
5202 /* convenience API for simple text combos */
5203
5204 /**
5205  * gtk_combo_box_new_text:
5206  *
5207  * Convenience function which constructs a new text combo box, which is a
5208  * #GtkComboBox just displaying strings. If you use this function to create
5209  * a text combo box, you should only manipulate its data source with the
5210  * following convenience functions: gtk_combo_box_append_text(),
5211  * gtk_combo_box_insert_text(), gtk_combo_box_prepend_text() and
5212  * gtk_combo_box_remove_text().
5213  *
5214  * Return value: (transfer none): A new text combo box.
5215  *
5216  * Since: 2.4
5217  */
5218 GtkWidget *
5219 gtk_combo_box_new_text (void)
5220 {
5221   GtkWidget *combo_box;
5222   GtkCellRenderer *cell;
5223   GtkListStore *store;
5224
5225   store = gtk_list_store_new (1, G_TYPE_STRING);
5226   combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
5227   g_object_unref (store);
5228
5229   cell = gtk_cell_renderer_text_new ();
5230   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
5231   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
5232                                   "text", 0,
5233                                   NULL);
5234
5235   return combo_box;
5236 }
5237
5238 /**
5239  * gtk_combo_box_append_text:
5240  * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text()
5241  * @text: A string
5242  *
5243  * Appends @string to the list of strings stored in @combo_box. Note that
5244  * you can only use this function with combo boxes constructed with
5245  * gtk_combo_box_new_text().
5246  *
5247  * Since: 2.4
5248  */
5249 void
5250 gtk_combo_box_append_text (GtkComboBox *combo_box,
5251                            const gchar *text)
5252 {
5253   GtkTreeIter iter;
5254   GtkListStore *store;
5255
5256   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5257   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
5258   g_return_if_fail (gtk_tree_model_get_column_type (combo_box->priv->model, 0)
5259                     == G_TYPE_STRING);
5260   g_return_if_fail (text != NULL);
5261
5262   store = GTK_LIST_STORE (combo_box->priv->model);
5263
5264   gtk_list_store_append (store, &iter);
5265   gtk_list_store_set (store, &iter, 0, text, -1);
5266 }
5267
5268 /**
5269  * gtk_combo_box_insert_text:
5270  * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text()
5271  * @position: An index to insert @text
5272  * @text: A string
5273  *
5274  * Inserts @string at @position in the list of strings stored in @combo_box.
5275  * Note that you can only use this function with combo boxes constructed
5276  * with gtk_combo_box_new_text().
5277  *
5278  * Since: 2.4
5279  */
5280 void
5281 gtk_combo_box_insert_text (GtkComboBox *combo_box,
5282                            gint         position,
5283                            const gchar *text)
5284 {
5285   GtkTreeIter iter;
5286   GtkListStore *store;
5287
5288   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5289   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
5290   g_return_if_fail (position >= 0);
5291   g_return_if_fail (gtk_tree_model_get_column_type (combo_box->priv->model, 0)
5292                     == G_TYPE_STRING);
5293   g_return_if_fail (text != NULL);
5294
5295   store = GTK_LIST_STORE (combo_box->priv->model);
5296
5297   gtk_list_store_insert (store, &iter, position);
5298   gtk_list_store_set (store, &iter, 0, text, -1);
5299 }
5300
5301 /**
5302  * gtk_combo_box_prepend_text:
5303  * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text()
5304  * @text: A string
5305  *
5306  * Prepends @string to the list of strings stored in @combo_box. Note that
5307  * you can only use this function with combo boxes constructed with
5308  * gtk_combo_box_new_text().
5309  *
5310  * Since: 2.4
5311  */
5312 void
5313 gtk_combo_box_prepend_text (GtkComboBox *combo_box,
5314                             const gchar *text)
5315 {
5316   GtkTreeIter iter;
5317   GtkListStore *store;
5318
5319   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5320   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
5321   g_return_if_fail (gtk_tree_model_get_column_type (combo_box->priv->model, 0)
5322                     == G_TYPE_STRING);
5323   g_return_if_fail (text != NULL);
5324
5325   store = GTK_LIST_STORE (combo_box->priv->model);
5326
5327   gtk_list_store_prepend (store, &iter);
5328   gtk_list_store_set (store, &iter, 0, text, -1);
5329 }
5330
5331 /**
5332  * gtk_combo_box_remove_text:
5333  * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text()
5334  * @position: Index of the item to remove
5335  *
5336  * Removes the string at @position from @combo_box. Note that you can only use
5337  * this function with combo boxes constructed with gtk_combo_box_new_text().
5338  *
5339  * Since: 2.4
5340  */
5341 void
5342 gtk_combo_box_remove_text (GtkComboBox *combo_box,
5343                            gint         position)
5344 {
5345   GtkTreeIter iter;
5346   GtkListStore *store;
5347
5348   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5349   g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
5350   g_return_if_fail (gtk_tree_model_get_column_type (combo_box->priv->model, 0)
5351                     == G_TYPE_STRING);
5352   g_return_if_fail (position >= 0);
5353
5354   store = GTK_LIST_STORE (combo_box->priv->model);
5355
5356   if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter,
5357                                      NULL, position))
5358     gtk_list_store_remove (store, &iter);
5359 }
5360
5361 /**
5362  * gtk_combo_box_get_active_text:
5363  * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text()
5364  *
5365  * Returns the currently active string in @combo_box or %NULL if none
5366  * is selected.  Note that you can only use this function with combo
5367  * boxes constructed with gtk_combo_box_new_text() and with
5368  * #GtkComboBoxEntry<!-- -->s.
5369  *
5370  * Returns: a newly allocated string containing the currently active text.
5371  *     Must be freed with g_free().
5372  *
5373  * Since: 2.6
5374  */
5375 gchar *
5376 gtk_combo_box_get_active_text (GtkComboBox *combo_box)
5377 {
5378   GtkComboBoxClass *class;
5379
5380   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
5381
5382   class = GTK_COMBO_BOX_GET_CLASS (combo_box);
5383
5384   if (class->get_active_text)
5385     return class->get_active_text (combo_box);
5386
5387   return NULL;
5388 }
5389
5390 static gchar *
5391 gtk_combo_box_real_get_active_text (GtkComboBox *combo_box)
5392 {
5393   GtkTreeIter iter;
5394   gchar *text = NULL;
5395
5396   g_return_val_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model), NULL);
5397   g_return_val_if_fail (gtk_tree_model_get_column_type (combo_box->priv->model, 0)
5398                         == G_TYPE_STRING, NULL);
5399
5400   if (gtk_combo_box_get_active_iter (combo_box, &iter))
5401     gtk_tree_model_get (combo_box->priv->model, &iter, 
5402                         0, &text, -1);
5403
5404   return text;
5405 }
5406
5407 static void
5408 gtk_combo_box_real_move_active (GtkComboBox   *combo_box,
5409                                 GtkScrollType  scroll)
5410 {
5411   GtkTreeIter iter;
5412   GtkTreeIter new_iter;
5413   gboolean    active_iter;
5414   gboolean    found;
5415
5416   if (!combo_box->priv->model)
5417     {
5418       gtk_widget_error_bell (GTK_WIDGET (combo_box));
5419       return;
5420     }
5421
5422   active_iter = gtk_combo_box_get_active_iter (combo_box, &iter);
5423
5424   switch (scroll)
5425     {
5426     case GTK_SCROLL_STEP_BACKWARD:
5427     case GTK_SCROLL_STEP_UP:
5428     case GTK_SCROLL_STEP_LEFT:
5429       if (active_iter)
5430         {
5431           found = tree_prev (combo_box, combo_box->priv->model,
5432                              &iter, &new_iter, FALSE);
5433           break;
5434         }
5435       /* else fall through */
5436
5437     case GTK_SCROLL_PAGE_FORWARD:
5438     case GTK_SCROLL_PAGE_DOWN:
5439     case GTK_SCROLL_PAGE_RIGHT:
5440     case GTK_SCROLL_END:
5441       found = tree_last (combo_box, combo_box->priv->model, &new_iter, FALSE);
5442       break;
5443
5444     case GTK_SCROLL_STEP_FORWARD:
5445     case GTK_SCROLL_STEP_DOWN:
5446     case GTK_SCROLL_STEP_RIGHT:
5447       if (active_iter)
5448         {
5449           found = tree_next (combo_box, combo_box->priv->model,
5450                              &iter, &new_iter, FALSE);
5451           break;
5452         }
5453       /* else fall through */
5454
5455     case GTK_SCROLL_PAGE_BACKWARD:
5456     case GTK_SCROLL_PAGE_UP:
5457     case GTK_SCROLL_PAGE_LEFT:
5458     case GTK_SCROLL_START:
5459       found = tree_first (combo_box, combo_box->priv->model, &new_iter, FALSE);
5460       break;
5461
5462     default:
5463       return;
5464     }
5465
5466   if (found && active_iter)
5467     {
5468       GtkTreePath *old_path;
5469       GtkTreePath *new_path;
5470
5471       old_path = gtk_tree_model_get_path (combo_box->priv->model, &iter);
5472       new_path = gtk_tree_model_get_path (combo_box->priv->model, &new_iter);
5473
5474       if (gtk_tree_path_compare (old_path, new_path) == 0)
5475         found = FALSE;
5476
5477       gtk_tree_path_free (old_path);
5478       gtk_tree_path_free (new_path);
5479     }
5480
5481   if (found)
5482     {
5483       gtk_combo_box_set_active_iter (combo_box, &new_iter);
5484     }
5485   else
5486     {
5487       gtk_widget_error_bell (GTK_WIDGET (combo_box));
5488     }
5489 }
5490
5491 static gboolean
5492 gtk_combo_box_mnemonic_activate (GtkWidget *widget,
5493                                  gboolean   group_cycling)
5494 {
5495   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
5496
5497   gtk_widget_grab_focus (combo_box->priv->button);
5498
5499   return TRUE;
5500 }
5501
5502 static void
5503 gtk_combo_box_grab_focus (GtkWidget *widget)
5504 {
5505   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
5506
5507   gtk_widget_grab_focus (combo_box->priv->button);
5508 }
5509
5510 static void
5511 gtk_combo_box_destroy (GtkObject *object)
5512 {
5513   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
5514
5515   if (combo_box->priv->popup_idle_id > 0)
5516     {
5517       g_source_remove (combo_box->priv->popup_idle_id);
5518       combo_box->priv->popup_idle_id = 0;
5519     }
5520
5521   gtk_combo_box_popdown (combo_box);
5522
5523   if (combo_box->priv->row_separator_destroy)
5524     combo_box->priv->row_separator_destroy (combo_box->priv->row_separator_data);
5525
5526   combo_box->priv->row_separator_func = NULL;
5527   combo_box->priv->row_separator_data = NULL;
5528   combo_box->priv->row_separator_destroy = NULL;
5529
5530   GTK_OBJECT_CLASS (gtk_combo_box_parent_class)->destroy (object);
5531   combo_box->priv->cell_view = NULL;
5532 }
5533
5534 static void
5535 gtk_combo_box_dispose(GObject* object)
5536 {
5537   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
5538
5539   if (GTK_IS_MENU (combo_box->priv->popup_widget))
5540     {
5541       gtk_combo_box_menu_destroy (combo_box);
5542       gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget));
5543       combo_box->priv->popup_widget = NULL;
5544     }
5545
5546   G_OBJECT_CLASS (gtk_combo_box_parent_class)->dispose (object);
5547 }
5548
5549 static void
5550 gtk_combo_box_finalize (GObject *object)
5551 {
5552   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
5553   GSList *i;
5554   
5555   if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
5556     gtk_combo_box_list_destroy (combo_box);
5557
5558   if (combo_box->priv->popup_window)
5559     gtk_widget_destroy (combo_box->priv->popup_window);
5560
5561   gtk_combo_box_unset_model (combo_box);
5562
5563   for (i = combo_box->priv->cells; i; i = i->next)
5564     {
5565       ComboCellInfo *info = (ComboCellInfo *)i->data;
5566       GSList *list = info->attributes;
5567
5568       if (info->destroy)
5569         info->destroy (info->func_data);
5570
5571       while (list && list->next)
5572         {
5573           g_free (list->data);
5574           list = list->next->next;
5575         }
5576       g_slist_free (info->attributes);
5577
5578       g_object_unref (info->cell);
5579       g_slice_free (ComboCellInfo, info);
5580     }
5581    g_slist_free (combo_box->priv->cells);
5582
5583    g_free (combo_box->priv->tearoff_title);
5584
5585    G_OBJECT_CLASS (gtk_combo_box_parent_class)->finalize (object);
5586 }
5587
5588 static gboolean
5589 gtk_cell_editable_key_press (GtkWidget   *widget,
5590                              GdkEventKey *event,
5591                              gpointer     data)
5592 {
5593   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
5594
5595   if (event->keyval == GDK_Escape)
5596     {
5597       g_object_set (combo_box,
5598                     "editing-canceled", TRUE,
5599                     NULL);
5600       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo_box));
5601       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo_box));
5602       
5603       return TRUE;
5604     }
5605   else if (event->keyval == GDK_Return ||
5606            event->keyval == GDK_ISO_Enter ||
5607            event->keyval == GDK_KP_Enter)
5608     {
5609       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo_box));
5610       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo_box));
5611       
5612       return TRUE;
5613     }
5614
5615   return FALSE;
5616 }
5617
5618 static gboolean
5619 popdown_idle (gpointer data)
5620 {
5621   GtkComboBox *combo_box;
5622
5623   combo_box = GTK_COMBO_BOX (data);
5624   
5625   gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo_box));
5626   gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo_box));
5627
5628   g_object_unref (combo_box);
5629
5630   return FALSE;
5631 }
5632
5633 static void
5634 popdown_handler (GtkWidget *widget,
5635                  gpointer   data)
5636 {
5637   gdk_threads_add_idle (popdown_idle, g_object_ref (data));
5638 }
5639
5640 static gboolean
5641 popup_idle (gpointer data)
5642 {
5643   GtkComboBox *combo_box;
5644
5645   combo_box = GTK_COMBO_BOX (data);
5646
5647   if (GTK_IS_MENU (combo_box->priv->popup_widget) &&
5648       combo_box->priv->cell_view)
5649     g_signal_connect_object (combo_box->priv->popup_widget,
5650                              "unmap", G_CALLBACK (popdown_handler),
5651                              combo_box, 0);
5652   
5653   /* we unset this if a menu item is activated */
5654   g_object_set (combo_box,
5655                 "editing-canceled", TRUE,
5656                 NULL);
5657   gtk_combo_box_popup (combo_box);
5658
5659   combo_box->priv->popup_idle_id = 0;
5660   combo_box->priv->activate_button = 0;
5661   combo_box->priv->activate_time = 0;
5662
5663   return FALSE;
5664 }
5665
5666 static void
5667 gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
5668                              GdkEvent        *event)
5669 {
5670   GtkComboBox *combo_box = GTK_COMBO_BOX (cell_editable);
5671
5672   combo_box->priv->is_cell_renderer = TRUE;
5673
5674   if (combo_box->priv->cell_view)
5675     {
5676       g_signal_connect_object (combo_box->priv->button, "key-press-event",
5677                                G_CALLBACK (gtk_cell_editable_key_press), 
5678                                cell_editable, 0);  
5679
5680       gtk_widget_grab_focus (combo_box->priv->button);
5681     }
5682   else
5683     {
5684       g_signal_connect_object (GTK_BIN (combo_box)->child, "key-press-event",
5685                                G_CALLBACK (gtk_cell_editable_key_press), 
5686                                cell_editable, 0);  
5687
5688       gtk_widget_grab_focus (GTK_WIDGET (GTK_BIN (combo_box)->child));
5689       gtk_widget_set_can_focus (combo_box->priv->button, FALSE);
5690     }
5691
5692   /* we do the immediate popup only for the optionmenu-like 
5693    * appearance 
5694    */  
5695   if (combo_box->priv->is_cell_renderer && 
5696       combo_box->priv->cell_view && !combo_box->priv->tree_view)
5697     {
5698       if (event && event->type == GDK_BUTTON_PRESS)
5699         {
5700           GdkEventButton *event_button = (GdkEventButton *)event;
5701
5702           combo_box->priv->activate_button = event_button->button;
5703           combo_box->priv->activate_time = event_button->time;
5704         }
5705
5706       combo_box->priv->popup_idle_id = 
5707           gdk_threads_add_idle (popup_idle, combo_box);
5708     }
5709 }
5710
5711
5712 /**
5713  * gtk_combo_box_get_add_tearoffs:
5714  * @combo_box: a #GtkComboBox
5715  * 
5716  * Gets the current value of the :add-tearoffs property.
5717  * 
5718  * Return value: the current value of the :add-tearoffs property.
5719  */
5720 gboolean
5721 gtk_combo_box_get_add_tearoffs (GtkComboBox *combo_box)
5722 {
5723   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
5724
5725   return combo_box->priv->add_tearoffs;
5726 }
5727
5728 /**
5729  * gtk_combo_box_set_add_tearoffs:
5730  * @combo_box: a #GtkComboBox 
5731  * @add_tearoffs: %TRUE to add tearoff menu items
5732  *  
5733  * Sets whether the popup menu should have a tearoff 
5734  * menu item.
5735  *
5736  * Since: 2.6
5737  */
5738 void
5739 gtk_combo_box_set_add_tearoffs (GtkComboBox *combo_box,
5740                                 gboolean     add_tearoffs)
5741 {
5742   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5743
5744   add_tearoffs = add_tearoffs != FALSE;
5745
5746   if (combo_box->priv->add_tearoffs != add_tearoffs)
5747     {
5748       combo_box->priv->add_tearoffs = add_tearoffs;
5749       gtk_combo_box_check_appearance (combo_box);
5750       gtk_combo_box_relayout (combo_box);
5751       g_object_notify (G_OBJECT (combo_box), "add-tearoffs");
5752     }
5753 }
5754
5755 /**
5756  * gtk_combo_box_get_title:
5757  * @combo_box: a #GtkComboBox
5758  *
5759  * Gets the current title of the menu in tearoff mode. See
5760  * gtk_combo_box_set_add_tearoffs().
5761  *
5762  * Returns: the menu's title in tearoff mode. This is an internal copy of the
5763  * string which must not be freed.
5764  *
5765  * Since: 2.10
5766  */
5767 G_CONST_RETURN gchar*
5768 gtk_combo_box_get_title (GtkComboBox *combo_box)
5769 {
5770   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
5771   
5772   return combo_box->priv->tearoff_title;
5773 }
5774
5775 static void
5776 gtk_combo_box_update_title (GtkComboBox *combo_box)
5777 {
5778   gtk_combo_box_check_appearance (combo_box);
5779   
5780   if (combo_box->priv->popup_widget && 
5781       GTK_IS_MENU (combo_box->priv->popup_widget))
5782     gtk_menu_set_title (GTK_MENU (combo_box->priv->popup_widget), 
5783                         combo_box->priv->tearoff_title);
5784 }
5785
5786 /**
5787  * gtk_combo_box_set_title:
5788  * @combo_box: a #GtkComboBox 
5789  * @title: a title for the menu in tearoff mode
5790  *  
5791  * Sets the menu's title in tearoff mode.
5792  *
5793  * Since: 2.10
5794  */
5795 void
5796 gtk_combo_box_set_title (GtkComboBox *combo_box,
5797                          const gchar *title)
5798 {
5799   GtkComboBoxPrivate *priv;
5800
5801   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5802
5803   priv = combo_box->priv;
5804
5805   if (strcmp (title ? title : "", 
5806               priv->tearoff_title ? priv->tearoff_title : "") != 0)
5807     {
5808       g_free (priv->tearoff_title);
5809       priv->tearoff_title = g_strdup (title);
5810
5811       gtk_combo_box_update_title (combo_box);
5812
5813       g_object_notify (G_OBJECT (combo_box), "tearoff-title");
5814     }
5815 }
5816
5817 /**
5818  * gtk_combo_box_get_popup_accessible:
5819  * @combo_box: a #GtkComboBox
5820  *
5821  * Gets the accessible object corresponding to the combo box's popup.
5822  *
5823  * This function is mostly intended for use by accessibility technologies;
5824  * applications should have little use for it.
5825  *
5826  * Returns: the accessible object corresponding to the combo box's popup.
5827  *
5828  * Since: 2.6
5829  */
5830 AtkObject*
5831 gtk_combo_box_get_popup_accessible (GtkComboBox *combo_box)
5832 {
5833   AtkObject *atk_obj;
5834
5835   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
5836
5837   if (combo_box->priv->popup_widget)
5838     {
5839       atk_obj = gtk_widget_get_accessible (combo_box->priv->popup_widget);
5840       return atk_obj;
5841     }
5842
5843   return NULL;
5844 }
5845
5846 /**
5847  * gtk_combo_box_get_row_separator_func:
5848  * @combo_box: a #GtkComboBox
5849  * 
5850  * Returns the current row separator function.
5851  * 
5852  * Return value: the current row separator function.
5853  *
5854  * Since: 2.6
5855  */
5856 GtkTreeViewRowSeparatorFunc 
5857 gtk_combo_box_get_row_separator_func (GtkComboBox *combo_box)
5858 {
5859   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
5860
5861   return combo_box->priv->row_separator_func;
5862 }
5863
5864 /**
5865  * gtk_combo_box_set_row_separator_func:
5866  * @combo_box: a #GtkComboBox
5867  * @func: a #GtkTreeViewRowSeparatorFunc
5868  * @data: (allow-none): user data to pass to @func, or %NULL
5869  * @destroy: (allow-none): destroy notifier for @data, or %NULL
5870  * 
5871  * Sets the row separator function, which is used to determine
5872  * whether a row should be drawn as a separator. If the row separator
5873  * function is %NULL, no separators are drawn. This is the default value.
5874  *
5875  * Since: 2.6
5876  */
5877 void
5878 gtk_combo_box_set_row_separator_func (GtkComboBox                 *combo_box,
5879                                       GtkTreeViewRowSeparatorFunc  func,
5880                                       gpointer                     data,
5881                                       GDestroyNotify               destroy)
5882 {
5883   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5884
5885   if (combo_box->priv->row_separator_destroy)
5886     combo_box->priv->row_separator_destroy (combo_box->priv->row_separator_data);
5887
5888   combo_box->priv->row_separator_func = func;
5889   combo_box->priv->row_separator_data = data;
5890   combo_box->priv->row_separator_destroy = destroy;
5891
5892   if (combo_box->priv->tree_view)
5893     gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (combo_box->priv->tree_view), 
5894                                           func, data, NULL);
5895
5896   gtk_combo_box_relayout (combo_box);
5897
5898   gtk_widget_queue_draw (GTK_WIDGET (combo_box));
5899 }
5900
5901 /**
5902  * gtk_combo_box_set_button_sensitivity:
5903  * @combo_box: a #GtkComboBox
5904  * @sensitivity: specify the sensitivity of the dropdown button
5905  *
5906  * Sets whether the dropdown button of the combo box should be
5907  * always sensitive (%GTK_SENSITIVITY_ON), never sensitive (%GTK_SENSITIVITY_OFF)
5908  * or only if there is at least one item to display (%GTK_SENSITIVITY_AUTO).
5909  *
5910  * Since: 2.14
5911  **/
5912 void
5913 gtk_combo_box_set_button_sensitivity (GtkComboBox        *combo_box,
5914                                       GtkSensitivityType  sensitivity)
5915 {
5916   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5917
5918   if (combo_box->priv->button_sensitivity != sensitivity)
5919     {
5920       combo_box->priv->button_sensitivity = sensitivity;
5921       gtk_combo_box_update_sensitivity (combo_box);
5922
5923       g_object_notify (G_OBJECT (combo_box), "button-sensitivity");
5924     }
5925 }
5926
5927 /**
5928  * gtk_combo_box_get_button_sensitivity:
5929  * @combo_box: a #GtkComboBox
5930  *
5931  * Returns whether the combo box sets the dropdown button
5932  * sensitive or not when there are no items in the model.
5933  *
5934  * Return Value: %GTK_SENSITIVITY_ON if the dropdown button
5935  *    is sensitive when the model is empty, %GTK_SENSITIVITY_OFF
5936  *    if the button is always insensitive or
5937  *    %GTK_SENSITIVITY_AUTO if it is only sensitive as long as
5938  *    the model has one item to be selected.
5939  *
5940  * Since: 2.14
5941  **/
5942 GtkSensitivityType
5943 gtk_combo_box_get_button_sensitivity (GtkComboBox *combo_box)
5944 {
5945   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
5946
5947   return combo_box->priv->button_sensitivity;
5948 }
5949
5950
5951 /**
5952  * gtk_combo_box_set_focus_on_click:
5953  * @combo: a #GtkComboBox
5954  * @focus_on_click: whether the combo box grabs focus when clicked 
5955  *    with the mouse
5956  * 
5957  * Sets whether the combo box will grab focus when it is clicked with 
5958  * the mouse. Making mouse clicks not grab focus is useful in places 
5959  * like toolbars where you don't want the keyboard focus removed from 
5960  * the main area of the application.
5961  *
5962  * Since: 2.6
5963  */
5964 void
5965 gtk_combo_box_set_focus_on_click (GtkComboBox *combo_box,
5966                                   gboolean     focus_on_click)
5967 {
5968   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
5969   
5970   focus_on_click = focus_on_click != FALSE;
5971
5972   if (combo_box->priv->focus_on_click != focus_on_click)
5973     {
5974       combo_box->priv->focus_on_click = focus_on_click;
5975
5976       if (combo_box->priv->button)
5977         gtk_button_set_focus_on_click (GTK_BUTTON (combo_box->priv->button),
5978                                        focus_on_click);
5979       
5980       g_object_notify (G_OBJECT (combo_box), "focus-on-click");
5981     }
5982 }
5983
5984 /**
5985  * gtk_combo_box_get_focus_on_click:
5986  * @combo: a #GtkComboBox
5987  * 
5988  * Returns whether the combo box grabs focus when it is clicked 
5989  * with the mouse. See gtk_combo_box_set_focus_on_click().
5990  *
5991  * Return value: %TRUE if the combo box grabs focus when it is 
5992  *     clicked with the mouse.
5993  *
5994  * Since: 2.6
5995  */
5996 gboolean
5997 gtk_combo_box_get_focus_on_click (GtkComboBox *combo_box)
5998 {
5999   g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
6000   
6001   return combo_box->priv->focus_on_click;
6002 }
6003
6004
6005 static gboolean
6006 gtk_combo_box_buildable_custom_tag_start (GtkBuildable  *buildable,
6007                                           GtkBuilder    *builder,
6008                                           GObject       *child,
6009                                           const gchar   *tagname,
6010                                           GMarkupParser *parser,
6011                                           gpointer      *data)
6012 {
6013   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
6014                                                 tagname, parser, data))
6015     return TRUE;
6016
6017   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
6018                                                       tagname, parser, data);
6019 }
6020
6021 static void
6022 gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable,
6023                                         GtkBuilder   *builder,
6024                                         GObject      *child,
6025                                         const gchar  *tagname,
6026                                         gpointer     *data)
6027 {
6028   if (strcmp (tagname, "attributes") == 0)
6029     _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
6030                                                data);
6031   else
6032     parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
6033                                             data);
6034 }