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