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