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