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