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