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