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