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