gtkcombobox.c 164 KB
Newer Older
1 2 3
/* gtkcombobox.c
 * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
 *
4 5 6 7
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * 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 11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Library General Public License for more details.
13
 *
14 15
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
16 17 18 19
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

20
#include <config.h>
Kristian Rietveld's avatar
Kristian Rietveld committed
21
#include "gtkcombobox.h"
22 23 24

#include "gtkarrow.h"
#include "gtkbindings.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
25
#include "gtkcelllayout.h"
26
#include "gtkcellrenderertext.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
27
#include "gtkcellview.h"
28
#include "gtkeventbox.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
29
#include "gtkframe.h"
30
#include "gtkhbox.h"
31 32 33
#include "gtkliststore.h"
#include "gtkmain.h"
#include "gtkmenu.h"
34
#include "gtkscrolledwindow.h"
35
#include "gtkseparatormenuitem.h"
36
#include "gtktearoffmenuitem.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
37
#include "gtktogglebutton.h"
38
#include "gtktreeselection.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
39 40
#include "gtkvseparator.h"
#include "gtkwindow.h"
41
#include "gtkprivate.h"
42
#include "gtkmarshal.h"
43 44 45 46 47

#include <gdk/gdkkeysyms.h>

#include <gobject/gvaluecollector.h>

Kristian Rietveld's avatar
Kristian Rietveld committed
48
#include <string.h>
49 50 51 52 53
#include <stdarg.h>

#include "gtkmarshalers.h"
#include "gtkintl.h"

54
#include "gtktreeprivate.h"
55
#include "gtkalias.h"
56 57 58 59 60 61 62 63 64

/* WELCOME, to THE house of evil code */

typedef struct _ComboCellInfo ComboCellInfo;
struct _ComboCellInfo
{
  GtkCellRenderer *cell;
  GSList *attributes;

65 66 67 68
  GtkCellLayoutDataFunc func;
  gpointer func_data;
  GDestroyNotify destroy;

69 70 71 72
  guint expand : 1;
  guint pack : 1;
};

73 74
#define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate))

75 76 77 78 79 80 81 82
struct _GtkComboBoxPrivate
{
  GtkTreeModel *model;

  gint col_column;
  gint row_column;

  gint wrap_width;
83
  GtkShadowType shadow_type;
84

85
  GtkTreeRowReference *active_row;
86 87 88 89 90 91 92 93

  GtkWidget *tree_view;
  GtkTreeViewColumn *column;

  GtkWidget *cell_view;
  GtkWidget *cell_view_frame;

  GtkWidget *button;
94
  GtkWidget *box;
95 96 97 98 99
  GtkWidget *arrow;
  GtkWidget *separator;

  GtkWidget *popup_widget;
  GtkWidget *popup_window;
100
  GtkWidget *scrolled_window;
101 102 103

  guint inserted_id;
  guint deleted_id;
104 105
  guint reordered_id;
  guint changed_id;
106
  guint popup_idle_id;
107 108
  guint activate_button;
  guint32 activate_time;
109
  guint scroll_timer;
110
  guint resize_idle_id;
111 112

  gint width;
113
  gint height;
114 115 116
  GSList *cells;

  guint popup_in_progress : 1;
117
  guint popup_shown : 1;
118
  guint add_tearoffs : 1;
119 120 121
  guint has_frame : 1;
  guint is_cell_renderer : 1;
  guint editing_canceled : 1;
122
  guint auto_scroll : 1;
Matthias Clasen's avatar
Matthias Clasen committed
123
  guint focus_on_click : 1;
124 125 126 127

  GtkTreeViewRowSeparatorFunc row_separator_func;
  gpointer                    row_separator_data;
  GtkDestroyNotify            row_separator_destroy;
128 129

  gchar *tearoff_title;
130 131
};

132 133 134 135 136 137 138 139 140 141 142 143 144 145
/* While debugging this evil code, I have learned that
 * there are actually 4 modes to this widget, which can
 * be characterized as follows
 * 
 * 1) menu mode, no child added
 *
 * tree_view -> NULL
 * cell_view -> GtkCellView, regular child
 * cell_view_frame -> NULL
 * button -> GtkToggleButton set_parent to combo
 * arrow -> GtkArrow set_parent to button
 * separator -> GtkVSepator set_parent to button
 * popup_widget -> GtkMenu
 * popup_window -> NULL
146
 * scrolled_window -> NULL
147 148 149 150 151 152 153 154 155 156 157
 *
 * 2) menu mode, child added
 * 
 * tree_view -> NULL
 * cell_view -> NULL 
 * cell_view_frame -> NULL
 * button -> GtkToggleButton set_parent to combo
 * arrow -> GtkArrow, child of button
 * separator -> NULL
 * popup_widget -> GtkMenu
 * popup_window -> NULL
158
 * scrolled_window -> NULL
159 160 161
 *
 * 3) list mode, no child added
 * 
162
 * tree_view -> GtkTreeView, child of scrolled_window
163 164 165 166 167 168 169
 * cell_view -> GtkCellView, regular child
 * cell_view_frame -> GtkFrame, set parent to combo
 * button -> GtkToggleButton, set_parent to combo
 * arrow -> GtkArrow, child of button
 * separator -> NULL
 * popup_widget -> tree_view
 * popup_window -> GtkWindow
170
 * scrolled_window -> GtkScrolledWindow, child of popup_window
171 172 173
 *
 * 4) list mode, child added
 *
174
 * tree_view -> GtkTreeView, child of scrolled_window
175 176 177 178 179 180 181
 * cell_view -> NULL
 * cell_view_frame -> NULL
 * button -> GtkToggleButton, set_parent to combo
 * arrow -> GtkArrow, child of button
 * separator -> NULL
 * popup_widget -> tree_view
 * popup_window -> GtkWindow
182
 * scrolled_window -> GtkScrolledWindow, child of popup_window
183 184 185
 * 
 */

186 187
enum {
  CHANGED,
188 189
  MOVE_ACTIVE,
  POPUP,
190
  POPDOWN,
191 192 193 194 195 196 197 198 199
  LAST_SIGNAL
};

enum {
  PROP_0,
  PROP_MODEL,
  PROP_WRAP_WIDTH,
  PROP_ROW_SPAN_COLUMN,
  PROP_COLUMN_SPAN_COLUMN,
200
  PROP_ACTIVE,
201
  PROP_ADD_TEAROFFS,
202
  PROP_TEAROFF_TITLE,
Matthias Clasen's avatar
Matthias Clasen committed
203
  PROP_HAS_FRAME,
204 205
  PROP_FOCUS_ON_CLICK,
  PROP_POPUP_SHOWN
206 207 208 209 210
};

static guint combo_box_signals[LAST_SIGNAL] = {0,};

#define BONUS_PADDING 4
211
#define SCROLL_TIME  100
212 213

/* common */
214

215
static void     gtk_combo_box_cell_layout_init     (GtkCellLayoutIface *iface);
216
static void     gtk_combo_box_cell_editable_init   (GtkCellEditableIface *iface);
217
static void     gtk_combo_box_dispose              (GObject          *object);
218 219
static void     gtk_combo_box_finalize             (GObject          *object);
static void     gtk_combo_box_destroy              (GtkObject        *object);
220 221 222 223 224 225 226 227 228 229

static void     gtk_combo_box_set_property         (GObject         *object,
                                                    guint            prop_id,
                                                    const GValue    *value,
                                                    GParamSpec      *spec);
static void     gtk_combo_box_get_property         (GObject         *object,
                                                    guint            prop_id,
                                                    GValue          *value,
                                                    GParamSpec      *spec);

230
static void     gtk_combo_box_state_changed        (GtkWidget        *widget,
231 232
			                            GtkStateType      previous);
static void     gtk_combo_box_grab_focus           (GtkWidget       *widget);
233
static void     gtk_combo_box_style_set            (GtkWidget       *widget,
234
                                                    GtkStyle        *previous);
235 236
static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
                                                    gpointer         data);
237 238 239
static void     gtk_combo_box_button_state_changed (GtkWidget       *widget,
			                            GtkStateType     previous,
						    gpointer         data);
240 241
static void     gtk_combo_box_add                  (GtkContainer    *container,
                                                    GtkWidget       *widget);
242 243
static void     gtk_combo_box_remove               (GtkContainer    *container,
                                                    GtkWidget       *widget);
244 245 246 247 248 249 250 251 252 253 254

static ComboCellInfo *gtk_combo_box_get_cell_info  (GtkComboBox      *combo_box,
                                                    GtkCellRenderer  *cell);

static void     gtk_combo_box_menu_show            (GtkWidget        *menu,
                                                    gpointer          user_data);
static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
                                                    gpointer          user_data);

static void     gtk_combo_box_set_popup_widget     (GtkComboBox      *combo_box,
                                                    GtkWidget        *popup);
255 256 257 258 259 260 261 262 263 264
static void     gtk_combo_box_menu_position_below  (GtkMenu          *menu,
                                                    gint             *x,
                                                    gint             *y,
                                                    gint             *push_in,
                                                    gpointer          user_data);
static void     gtk_combo_box_menu_position_over   (GtkMenu          *menu,
                                                    gint             *x,
                                                    gint             *y,
                                                    gint             *push_in,
                                                    gpointer          user_data);
265 266 267 268 269 270 271 272
static void     gtk_combo_box_menu_position        (GtkMenu          *menu,
                                                    gint             *x,
                                                    gint             *y,
                                                    gint             *push_in,
                                                    gpointer          user_data);

static gint     gtk_combo_box_calc_requested_width (GtkComboBox      *combo_box,
                                                    GtkTreePath      *path);
273
static void     gtk_combo_box_remeasure            (GtkComboBox      *combo_box);
274

275 276
static void     gtk_combo_box_unset_model          (GtkComboBox      *combo_box);

277 278 279 280 281 282 283 284 285 286
static void     gtk_combo_box_size_request         (GtkWidget        *widget,
                                                    GtkRequisition   *requisition);
static void     gtk_combo_box_size_allocate        (GtkWidget        *widget,
                                                    GtkAllocation    *allocation);
static void     gtk_combo_box_forall               (GtkContainer     *container,
                                                    gboolean          include_internals,
                                                    GtkCallback       callback,
                                                    gpointer          callback_data);
static gboolean gtk_combo_box_expose_event         (GtkWidget        *widget,
                                                    GdkEventExpose   *event);
287 288
static gboolean gtk_combo_box_scroll_event         (GtkWidget        *widget,
                                                    GdkEventScroll   *event);
289
static void     gtk_combo_box_set_active_internal  (GtkComboBox      *combo_box,
290
						    GtkTreePath      *path);
291

292
static void     gtk_combo_box_check_appearance     (GtkComboBox      *combo_box);
293
static gchar *  gtk_combo_box_real_get_active_text (GtkComboBox      *combo_box);
294 295 296
static void     gtk_combo_box_real_move_active     (GtkComboBox      *combo_box,
                                                    GtkScrollType     scroll);
static void     gtk_combo_box_real_popup           (GtkComboBox      *combo_box);
297
static gboolean gtk_combo_box_real_popdown         (GtkComboBox      *combo_box);
298

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
/* listening to the model */
static void     gtk_combo_box_model_row_inserted   (GtkTreeModel     *model,
						    GtkTreePath      *path,
						    GtkTreeIter      *iter,
						    gpointer          user_data);
static void     gtk_combo_box_model_row_deleted    (GtkTreeModel     *model,
						    GtkTreePath      *path,
						    gpointer          user_data);
static void     gtk_combo_box_model_rows_reordered (GtkTreeModel     *model,
						    GtkTreePath      *path,
						    GtkTreeIter      *iter,
						    gint             *new_order,
						    gpointer          user_data);
static void     gtk_combo_box_model_row_changed    (GtkTreeModel     *model,
						    GtkTreePath      *path,
						    GtkTreeIter      *iter,
						    gpointer          data);
316 317 318 319
static void     gtk_combo_box_model_row_expanded   (GtkTreeModel     *model,
						    GtkTreePath      *path,
						    GtkTreeIter      *iter,
						    gpointer          data);
320

321
/* list */
322 323 324 325 326
static void     gtk_combo_box_list_position        (GtkComboBox      *combo_box, 
						    gint             *x, 
						    gint             *y, 
						    gint             *width,
						    gint             *height);
327 328 329 330 331 332 333 334 335
static void     gtk_combo_box_list_setup           (GtkComboBox      *combo_box);
static void     gtk_combo_box_list_destroy         (GtkComboBox      *combo_box);

static gboolean gtk_combo_box_list_button_released (GtkWidget        *widget,
                                                    GdkEventButton   *event,
                                                    gpointer          data);
static gboolean gtk_combo_box_list_key_press       (GtkWidget        *widget,
                                                    GdkEventKey      *event,
                                                    gpointer          data);
336 337 338 339 340 341 342
static gboolean gtk_combo_box_list_enter_notify    (GtkWidget        *widget,
                                                    GdkEventCrossing *event,
                                                    gpointer          data);
static void     gtk_combo_box_list_auto_scroll     (GtkComboBox   *combo,
						    gint           x,
						    gint           y);
static gboolean gtk_combo_box_list_scroll_timeout  (GtkComboBox   *combo);
343 344 345 346
static gboolean gtk_combo_box_list_button_pressed  (GtkWidget        *widget,
                                                    GdkEventButton   *event,
                                                    gpointer          data);

347 348 349 350 351 352
static gboolean gtk_combo_box_list_select_func     (GtkTreeSelection *selection,
						    GtkTreeModel     *model,
						    GtkTreePath      *path,
						    gboolean          path_currently_selected,
						    gpointer          data);

353 354 355 356
static void     gtk_combo_box_list_row_changed     (GtkTreeModel     *model,
                                                    GtkTreePath      *path,
                                                    GtkTreeIter      *iter,
                                                    gpointer          data);
357
static void     gtk_combo_box_list_popup_resize    (GtkComboBox      *combo_box);
358 359 360

/* menu */
static void     gtk_combo_box_menu_setup           (GtkComboBox      *combo_box,
361
                                                    gboolean          add_children);
362
static void     gtk_combo_box_menu_fill            (GtkComboBox      *combo_box);
363 364 365
static void     gtk_combo_box_menu_fill_level      (GtkComboBox      *combo_box,
						    GtkWidget        *menu,
						    GtkTreeIter      *iter);
366
static void     gtk_combo_box_update_title         (GtkComboBox      *combo_box);
367 368 369
static void     gtk_combo_box_menu_destroy         (GtkComboBox      *combo_box);

static void     gtk_combo_box_relayout_item        (GtkComboBox      *combo_box,
370 371 372
						    GtkWidget        *item,
                                                    GtkTreeIter      *iter,
						    GtkWidget        *last);
373 374 375 376 377 378 379 380 381 382 383 384 385 386
static void     gtk_combo_box_relayout             (GtkComboBox      *combo_box);

static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
                                                    GdkEventButton   *event,
                                                    gpointer          user_data);
static void     gtk_combo_box_menu_item_activate   (GtkWidget        *item,
                                                    gpointer          user_data);
static void     gtk_combo_box_menu_row_inserted    (GtkTreeModel     *model,
                                                    GtkTreePath      *path,
                                                    GtkTreeIter      *iter,
                                                    gpointer          user_data);
static void     gtk_combo_box_menu_row_deleted     (GtkTreeModel     *model,
                                                    GtkTreePath      *path,
                                                    gpointer          user_data);
387 388 389 390 391
static void     gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
						    GtkTreePath      *path,
						    GtkTreeIter      *iter,
						    gint             *new_order,
						    gpointer          user_data);
392 393 394 395
static void     gtk_combo_box_menu_row_changed     (GtkTreeModel     *model,
                                                    GtkTreePath      *path,
                                                    GtkTreeIter      *iter,
                                                    gpointer          data);
396 397 398
static gboolean gtk_combo_box_menu_key_press       (GtkWidget        *widget,
						    GdkEventKey      *event,
						    gpointer          data);
399 400 401 402 403 404
static void     gtk_combo_box_menu_popup           (GtkComboBox      *combo_box,
						    guint             button, 
						    guint32           activate_time);
static GtkWidget *gtk_cell_view_menu_item_new      (GtkComboBox      *combo_box,
						    GtkTreeModel     *model,
						    GtkTreeIter      *iter);
405

406 407 408 409 410 411 412
/* cell layout */
static void     gtk_combo_box_cell_layout_pack_start         (GtkCellLayout         *layout,
                                                              GtkCellRenderer       *cell,
                                                              gboolean               expand);
static void     gtk_combo_box_cell_layout_pack_end           (GtkCellLayout         *layout,
                                                              GtkCellRenderer       *cell,
                                                              gboolean               expand);
413
static GList   *gtk_combo_box_cell_layout_get_cells          (GtkCellLayout         *layout);
414 415 416 417 418 419 420 421 422 423 424 425
static void     gtk_combo_box_cell_layout_clear              (GtkCellLayout         *layout);
static void     gtk_combo_box_cell_layout_add_attribute      (GtkCellLayout         *layout,
                                                              GtkCellRenderer       *cell,
                                                              const gchar           *attribute,
                                                              gint                   column);
static void     gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
                                                              GtkCellRenderer       *cell,
                                                              GtkCellLayoutDataFunc  func,
                                                              gpointer               func_data,
                                                              GDestroyNotify         destroy);
static void     gtk_combo_box_cell_layout_clear_attributes   (GtkCellLayout         *layout,
                                                              GtkCellRenderer       *cell);
Kristian Rietveld's avatar
Kristian Rietveld committed
426 427 428
static void     gtk_combo_box_cell_layout_reorder            (GtkCellLayout         *layout,
                                                              GtkCellRenderer       *cell,
                                                              gint                   position);
429 430
static gboolean gtk_combo_box_mnemonic_activate              (GtkWidget    *widget,
							      gboolean      group_cycling);
431

432 433 434 435 436 437 438
static void     gtk_combo_box_sync_cells                     (GtkComboBox   *combo_box,
					                      GtkCellLayout *cell_layout);
static void     combo_cell_data_func                         (GtkCellLayout   *cell_layout,
							      GtkCellRenderer *cell,
							      GtkTreeModel    *tree_model,
							      GtkTreeIter     *iter,
							      gpointer         data);
439
static void     gtk_combo_box_child_show                     (GtkWidget       *widget,
440
							      GtkComboBox     *combo_box);
441
static void     gtk_combo_box_child_hide                     (GtkWidget       *widget,
442
							      GtkComboBox     *combo_box);
443

Johan Dahlin's avatar
Johan Dahlin committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
/* GtkBuildable method implementation */
static GtkBuildableIface *parent_buildable_iface;

static void     gtk_combo_box_buildable_init                 (GtkBuildableIface *iface);
static gboolean gtk_combo_box_buildable_custom_tag_start     (GtkBuildable  *buildable,
							      GtkBuilder    *builder,
							      GObject       *child,
							      const gchar   *tagname,
							      GMarkupParser *parser,
							      gpointer      *data);
static void     gtk_combo_box_buildable_custom_tag_end       (GtkBuildable  *buildable,
							      GtkBuilder    *builder,
							      GObject       *child,
							      const gchar   *tagname,
							      gpointer      *data);
459

460 461 462 463 464
/* GtkCellEditable method implementations */
static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
					 GdkEvent        *event);


Matthias Clasen's avatar
Matthias Clasen committed
465 466 467 468
G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
						gtk_combo_box_cell_layout_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
Johan Dahlin's avatar
Johan Dahlin committed
469 470 471 472
						gtk_combo_box_cell_editable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_combo_box_buildable_init))

473 474 475 476 477 478

/* common */
static void
gtk_combo_box_class_init (GtkComboBoxClass *klass)
{
  GObjectClass *object_class;
479
  GtkObjectClass *gtk_object_class;
480 481
  GtkContainerClass *container_class;
  GtkWidgetClass *widget_class;
482
  GtkBindingSet *binding_set;
483

484 485
  klass->get_active_text = gtk_combo_box_real_get_active_text;

486 487 488
  container_class = (GtkContainerClass *)klass;
  container_class->forall = gtk_combo_box_forall;
  container_class->add = gtk_combo_box_add;
489
  container_class->remove = gtk_combo_box_remove;
490 491 492 493 494

  widget_class = (GtkWidgetClass *)klass;
  widget_class->size_allocate = gtk_combo_box_size_allocate;
  widget_class->size_request = gtk_combo_box_size_request;
  widget_class->expose_event = gtk_combo_box_expose_event;
495
  widget_class->scroll_event = gtk_combo_box_scroll_event;
496
  widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
497
  widget_class->grab_focus = gtk_combo_box_grab_focus;
498
  widget_class->style_set = gtk_combo_box_style_set;
499
  widget_class->state_changed = gtk_combo_box_state_changed;
500

501 502 503
  gtk_object_class = (GtkObjectClass *)klass;
  gtk_object_class->destroy = gtk_combo_box_destroy;

504
  object_class = (GObjectClass *)klass;
505
  object_class->dispose = gtk_combo_box_dispose;
506
  object_class->finalize = gtk_combo_box_finalize;
507 508 509 510
  object_class->set_property = gtk_combo_box_set_property;
  object_class->get_property = gtk_combo_box_get_property;

  /* signals */
Matthias Clasen's avatar
Matthias Clasen committed
511 512 513 514
  /**
   * GtkComboBox::changed:
   * @widget: the object which received the signal
   * 
515
   * The changed signal is emitted when the active
Matthias Clasen's avatar
Matthias Clasen committed
516 517 518
   * item is changed. The can be due to the user selecting
   * a different item from the list, or due to a 
   * call to gtk_combo_box_set_active_iter().
519 520
   * It will also be emitted while typing into a GtkComboBoxEntry, 
   * as well as when selecting an item from the GtkComboBoxEntry's list.
Matthias Clasen's avatar
Matthias Clasen committed
521 522 523
   *
   * Since: 2.4
   */
524
  combo_box_signals[CHANGED] =
Matthias Clasen's avatar
Matthias Clasen committed
525
    g_signal_new (I_("changed"),
526 527 528 529 530 531
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkComboBoxClass, changed),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
532 533 534 535 536 537 538 539 540 541 542
  /**
   * GtkComboBox::move-active:
   * @widget: the object that received the signal
   * @scroll_type: a #GtkScrollType
   *
   * The ::move-active signal is a 
   * <link linkend="keybinding-signals">keybinding signal</link>
   * which gets emitted to move the active selection.
   *
   * Since: 2.12
   */
543 544 545 546 547 548 549 550 551 552
  combo_box_signals[MOVE_ACTIVE] =
    _gtk_binding_signal_new (I_("move-active"),
                             G_OBJECT_CLASS_TYPE (klass),
                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                             G_CALLBACK (gtk_combo_box_real_move_active),
                             NULL, NULL,
                             g_cclosure_marshal_VOID__ENUM,
                             G_TYPE_NONE, 1,
                             GTK_TYPE_SCROLL_TYPE);

553 554 555 556 557 558 559 560 561 562 563 564
  /**
   * GtkComboBox::popup:
   * @widget: the object that received the signal
   *
   * The ::popup signal is a 
   * <link linkend="keybinding-signals">keybinding signal</link>
   * which gets emitted to popup the combo box list.
   *
   * The default binding for this signal is Alt+Down.
   *
   * Since: 2.12
   */
565 566 567 568 569 570 571 572
  combo_box_signals[POPUP] =
    _gtk_binding_signal_new (I_("popup"),
                             G_OBJECT_CLASS_TYPE (klass),
                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                             G_CALLBACK (gtk_combo_box_real_popup),
                             NULL, NULL,
                             g_cclosure_marshal_VOID__VOID,
                             G_TYPE_NONE, 0);
573 574 575 576 577 578 579 580 581 582 583 584
  /**
   * GtkComboBox::popdown:
   * @button: the object which received the signal
   *
   * The ::popdown signal is a 
   * <link linkend="keybinding-signals">keybinding signal</link> 
   * which gets emitted to popdown the combo box list.
   *
   * The default bindings for this signal are Alt+Up and Escape.
   *
   * Since: 2.12
   */
585 586 587 588 589 590 591 592 593
  combo_box_signals[POPDOWN] =
    _gtk_binding_signal_new (I_("popdown"),
                             G_OBJECT_CLASS_TYPE (klass),
                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                             G_CALLBACK (gtk_combo_box_real_popdown),
                             NULL, NULL,
                             gtk_marshal_BOOLEAN__VOID,
                             G_TYPE_BOOLEAN, 0);

594 595 596 597 598
  /* key bindings */
  binding_set = gtk_binding_set_by_class (widget_class);

  gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_MOD1_MASK,
				"popup", 0);
599 600 601 602 603 604 605 606 607
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, GDK_MOD1_MASK,
				"popup", 0);

  gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_MOD1_MASK,
				"popdown", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, GDK_MOD1_MASK,
				"popdown", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
				"popdown", 0);
608 609

  gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
610
				"move-active", 1,
611 612
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_UP);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
613
				"move-active", 1,
614 615
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_UP);
  gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
616
				"move-active", 1,
617 618
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
619
				"move-active", 1,
620 621
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP);
  gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
622
				"move-active", 1,
623 624
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_START);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
625
				"move-active", 1,
626 627 628
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_START);

  gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
629
				"move-active", 1,
630 631
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_DOWN);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
632
				"move-active", 1,
633 634
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_DOWN);
  gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
635
				"move-active", 1,
636 637
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
638
				"move-active", 1,
639 640
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN);
  gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
641
				"move-active", 1,
642 643
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
644
				"move-active", 1,
645 646
				GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END);

647
  /* properties */
Matthias Clasen's avatar
Matthias Clasen committed
648 649 650 651 652 653 654 655
  /**
   * GtkComboBox:model:
   *
   * The model from which the combo box takes the values shown
   * in the list. 
   *
   * Since: 2.4
   */
656 657 658
  g_object_class_install_property (object_class,
                                   PROP_MODEL,
                                   g_param_spec_object ("model",
659 660
                                                        P_("ComboBox model"),
                                                        P_("The model for the combo box"),
661
                                                        GTK_TYPE_TREE_MODEL,
662
                                                        GTK_PARAM_READWRITE));
663

Matthias Clasen's avatar
Matthias Clasen committed
664 665 666 667 668 669 670 671 672
  /**
   * GtkComboBox:wrap-width:
   *
   * If wrap-width is set to a positive value, the list will be
   * displayed in multiple columns, the number of columns is
   * determined by wrap-width.
   *
   * Since: 2.4
   */
673 674
  g_object_class_install_property (object_class,
                                   PROP_WRAP_WIDTH,
675
                                   g_param_spec_int ("wrap-width",
676
                                                     P_("Wrap width"),
677
                                                     P_("Wrap width for laying out the items in a grid"),
678 679 680
                                                     0,
                                                     G_MAXINT,
                                                     0,
681
                                                     GTK_PARAM_READWRITE));
682

Matthias Clasen's avatar
Matthias Clasen committed
683 684 685 686 687 688 689

  /**
   * GtkComboBox:row-span-column:
   *
   * If this is set to a non-negative value, it must be the index of a column 
   * of type %G_TYPE_INT in the model. 
   *
Matthias Clasen's avatar
Matthias Clasen committed
690 691 692
   * The values of that column are used to determine how many rows a value in 
   * the list will span. Therefore, the values in the model column pointed to 
   * by this property must be greater than zero and not larger than wrap-width.
Matthias Clasen's avatar
Matthias Clasen committed
693 694 695
   *
   * Since: 2.4
   */
696 697
  g_object_class_install_property (object_class,
                                   PROP_ROW_SPAN_COLUMN,
698
                                   g_param_spec_int ("row-span-column",
699 700
                                                     P_("Row span column"),
                                                     P_("TreeModel column containing the row span values"),
701
                                                     -1,
702
                                                     G_MAXINT,
703
                                                     -1,
704
                                                     GTK_PARAM_READWRITE));
705

Matthias Clasen's avatar
Matthias Clasen committed
706 707 708 709 710 711 712 713 714 715 716 717

  /**
   * GtkComboBox:column-span-column:
   *
   * If this is set to a non-negative value, it must be the index of a column 
   * of type %G_TYPE_INT in the model. 
   *
   * The values of that column are used to determine how many columns a value 
   * in the list will span. 
   *
   * Since: 2.4
   */
718 719
  g_object_class_install_property (object_class,
                                   PROP_COLUMN_SPAN_COLUMN,
720
                                   g_param_spec_int ("column-span-column",
721 722
                                                     P_("Column span column"),
                                                     P_("TreeModel column containing the column span values"),
723
                                                     -1,
724
                                                     G_MAXINT,
725
                                                     -1,
726
                                                     GTK_PARAM_READWRITE));
727

728

Matthias Clasen's avatar
Matthias Clasen committed
729 730 731 732 733
  /**
   * GtkComboBox:active:
   *
   * The item which is currently active. If the model is a non-flat treemodel,
   * and the active item is not an immediate child of the root of the tree,
Matthias Clasen's avatar
Matthias Clasen committed
734 735
   * this property has the value 
   * <literal>gtk_tree_path_get_indices (path)[0]</literal>,
Matthias Clasen's avatar
Matthias Clasen committed
736 737 738 739
   * where <literal>path</literal> is the #GtkTreePath of the active item.
   *
   * Since: 2.4
   */
740 741 742
  g_object_class_install_property (object_class,
                                   PROP_ACTIVE,
                                   g_param_spec_int ("active",
743 744
                                                     P_("Active item"),
                                                     P_("The item which is currently active"),
745
                                                     -1,
746
                                                     G_MAXINT,
747
                                                     -1,
748
                                                     GTK_PARAM_READWRITE));
749

750 751 752
  /**
   * GtkComboBox:add-tearoffs:
   *
Matthias Clasen's avatar
Matthias Clasen committed
753
   * The add-tearoffs property controls whether generated menus 
754 755 756 757 758 759 760 761 762 763
   * have tearoff menu items. 
   *
   * Note that this only affects menu style combo boxes.
   *
   * Since: 2.6
   */
  g_object_class_install_property (object_class,
                                   PROP_ADD_TEAROFFS,
				   g_param_spec_boolean ("add-tearoffs",
							 P_("Add tearoffs to menus"),
764
							 P_("Whether dropdowns should have a tearoff menu item"),
765
							 FALSE,
766
							 GTK_PARAM_READWRITE));
767
  
768 769 770
  /**
   * GtkComboBox:has-frame:
   *
Matthias Clasen's avatar
Matthias Clasen committed
771
   * The has-frame property controls whether a frame
772 773 774 775 776 777 778 779 780 781
   * is drawn around the entry.
   *
   * Since: 2.6
   */
  g_object_class_install_property (object_class,
                                   PROP_HAS_FRAME,
				   g_param_spec_boolean ("has-frame",
							 P_("Has Frame"),
							 P_("Whether the combo box draws a frame around the child"),
							 TRUE,
782
							 GTK_PARAM_READWRITE));
783
  
Matthias Clasen's avatar
Matthias Clasen committed
784 785
  g_object_class_install_property (object_class,
                                   PROP_FOCUS_ON_CLICK,
786
                                   g_param_spec_boolean ("focus-on-click",
Matthias Clasen's avatar
Matthias Clasen committed
787 788 789
							 P_("Focus on click"),
							 P_("Whether the combo box grabs focus when it is clicked with the mouse"),
							 TRUE,
790
							 GTK_PARAM_READWRITE));
Matthias Clasen's avatar
Matthias Clasen committed
791

792 793 794 795 796 797 798 799 800 801 802 803 804
  /**
   * GtkComboBox:tearoff-title:
   *
   * A title that may be displayed by the window manager 
   * when the popup is torn-off.
   *
   * Since: 2.10
   */
  g_object_class_install_property (object_class,
                                   PROP_TEAROFF_TITLE,
                                   g_param_spec_string ("tearoff-title",
                                                        P_("Tearoff Title"),
                                                        P_("A title that may be displayed by the window manager when the popup is torn-off"),
805
                                                        NULL,
806 807 808
                                                        GTK_PARAM_READWRITE));


809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
  /**
   * GtkComboBox:popup-shown:
   *
   * Whether the combo boxes dropdown is popped up. 
   * Note that this property is mainly useful, because
   * it allows you to connect to notify::popup-shown.
   *
   * Since: 2.10
   */
  g_object_class_install_property (object_class,
                                   PROP_POPUP_SHOWN,
                                   g_param_spec_boolean ("popup-shown",
                                                         P_("Popup shown"),
                                                         P_("Whether the combo's dropdown is shown"),
                                                         FALSE,
                                                         GTK_PARAM_READABLE));
825

826
  gtk_widget_class_install_style_property (widget_class,
827 828
                                           g_param_spec_boolean ("appears-as-list",
                                                                 P_("Appears as list"),
829
                                                                 P_("Whether dropdowns should look like lists rather than menus"),
830
                                                                 FALSE,
831
                                                                 GTK_PARAM_READABLE));
832

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
  /**
   * GtkComboBox:arrow-size:
   *
   * Sets the minimum size of the arrow in the combo box.  Note
   * that the arrow size is coupled to the font size, so in case
   * a larger font is used, the arrow will be larger than set
   * by arrow size.
   *
   * Since: 2.12
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("arrow-size",
							     P_("Arrow Size"),
							     P_("The minimum size of the arrow in the combo box"),
							     0,
							     G_MAXINT,
							     15,
							     GTK_PARAM_READABLE));

852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
  /**
   * GtkComboBox:shadow-type:
   *
   * Which kind of shadow to draw around the combo box.
   *
   * Since: 2.12
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_enum ("shadow-type",
                                                              P_("Shadow type"),
                                                              P_("Which kind of shadow to draw around the combo box"),
                                                              GTK_TYPE_SHADOW_TYPE,
                                                              GTK_SHADOW_NONE,
                                                              GTK_PARAM_READABLE));

867 868 869
  g_type_class_add_private (object_class, sizeof (GtkComboBoxPrivate));
}

Johan Dahlin's avatar
Johan Dahlin committed
870 871 872 873
static void
gtk_combo_box_buildable_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);
874
  iface->add_child = _gtk_cell_layout_buildable_add_child;
Johan Dahlin's avatar
Johan Dahlin committed
875 876 877 878
  iface->custom_tag_start = gtk_combo_box_buildable_custom_tag_start;
  iface->custom_tag_end = gtk_combo_box_buildable_custom_tag_end;
}

879 880 881 882 883
static void
gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
{
  iface->pack_start = gtk_combo_box_cell_layout_pack_start;
  iface->pack_end = gtk_combo_box_cell_layout_pack_end;
884
  iface->get_cells = gtk_combo_box_cell_layout_get_cells;
885 886 887 888
  iface->clear = gtk_combo_box_cell_layout_clear;
  iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
  iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
  iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
Kristian Rietveld's avatar
Kristian Rietveld committed
889
  iface->reorder = gtk_combo_box_cell_layout_reorder;
890 891
}

892 893 894 895 896 897
static void
gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface)
{
  iface->start_editing = gtk_combo_box_start_editing;
}

898 899 900
static void
gtk_combo_box_init (GtkComboBox *combo_box)
{
901
  GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
902

903 904 905 906
  priv->cell_view = gtk_cell_view_new ();
  gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (combo_box));
  GTK_BIN (combo_box)->child = priv->cell_view;
  gtk_widget_show (priv->cell_view);
907

908 909 910
  priv->width = 0;
  priv->height = 0;
  priv->wrap_width = 0;
911

912 913 914
  priv->active_row = NULL;
  priv->col_column = -1;
  priv->row_column = -1;
915

916 917 918 919 920 921 922 923 924
  priv->popup_shown = FALSE;
  priv->add_tearoffs = FALSE;
  priv->has_frame = TRUE;
  priv->is_cell_renderer = FALSE;
  priv->editing_canceled = FALSE;
  priv->auto_scroll = FALSE;
  priv->focus_on_click = TRUE;

  combo_box->priv = priv;
925 926

  gtk_combo_box_check_appearance (combo_box);
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
}

static void
gtk_combo_box_set_property (GObject      *object,
                            guint         prop_id,
                            const GValue *value,
                            GParamSpec   *pspec)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (object);

  switch (prop_id)
    {
      case PROP_MODEL:
        gtk_combo_box_set_model (combo_box, g_value_get_object (value));
        break;

      case PROP_WRAP_WIDTH:
        gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
        break;

      case PROP_ROW_SPAN_COLUMN:
        gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
        break;

      case PROP_COLUMN_SPAN_COLUMN:
        gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
        break;

      case PROP_ACTIVE:
        gtk_combo_box_set_active (combo_box, g_value_get_int (value));
        break;

959 960 961 962
      case PROP_ADD_TEAROFFS:
        gtk_combo_box_set_add_tearoffs (combo_box, g_value_get_boolean (value));
        break;

963 964 965 966
      case PROP_HAS_FRAME:
        combo_box->priv->has_frame = g_value_get_boolean (value);
        break;

Matthias Clasen's avatar
Matthias Clasen committed
967
      case PROP_FOCUS_ON_CLICK:
968 969
	gtk_combo_box_set_focus_on_click (combo_box, 
					  g_value_get_boolean (value));
Matthias Clasen's avatar
Matthias Clasen committed
970 971
        break;

972 973 974 975
      case PROP_TEAROFF_TITLE:
	gtk_combo_box_set_title (combo_box, g_value_get_string (value));
        break;

976 977
      case PROP_POPUP_SHOWN:
        if (g_value_get_boolean (value))
978
          gtk_combo_box_popup (combo_box);
979
        else
980
          gtk_combo_box_popdown (combo_box);
981 982
        break;

983
      default:
984
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
        break;
    }
}

static void
gtk_combo_box_get_property (GObject    *object,
                            guint       prop_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (object);

  switch (prop_id)
    {
      case PROP_MODEL:
        g_value_set_object (value, combo_box->priv->model);
        break;

      case PROP_WRAP_WIDTH:
        g_value_set_int (value, combo_box->priv->wrap_width);
        break;

      case PROP_ROW_SPAN_COLUMN:
        g_value_set_int (value, combo_box->priv->row_column);
        break;

      case PROP_COLUMN_SPAN_COLUMN:
        g_value_set_int (value, combo_box->priv->col_column);
        break;

      case PROP_ACTIVE:
        g_value_set_int (value, gtk_combo_box_get_active (combo_box));
        break;

1019 1020 1021 1022
      case PROP_ADD_TEAROFFS:
        g_value_set_boolean (value, gtk_combo_box_get_add_tearoffs (combo_box));
        break;

1023 1024 1025 1026
      case PROP_HAS_FRAME:
        g_value_set_boolean (value, combo_box->priv->has_frame);
        break;

Matthias Clasen's avatar
Matthias Clasen committed
1027 1028 1029 1030
      case PROP_FOCUS_ON_CLICK:
        g_value_set_boolean (value, combo_box->priv->focus_on_click);
        break;

1031 1032 1033 1034
      case PROP_TEAROFF_TITLE:
        g_value_set_string (value, gtk_combo_box_get_title (combo_box));
        break;

1035 1036 1037 1038
      case PROP_POPUP_SHOWN:
        g_value_set_boolean (value, combo_box->priv->popup_shown);
        break;

1039 1040 1041 1042 1043 1044
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

1045 1046 1047 1048 1049
static void
gtk_combo_box_state_changed (GtkWidget    *widget,
			     GtkStateType  previous)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1050
  GtkComboBoxPrivate *priv = combo_box->priv;
1051 1052 1053

  if (GTK_WIDGET_REALIZED (widget))
    {
1054 1055
      if (priv->tree_view && priv->cell_view)
	gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
1056 1057 1058 1059 1060 1061
					    &widget->style->base[GTK_WIDGET_STATE (widget)]);
    }

  gtk_widget_queue_draw (widget);
}

1062 1063 1064 1065 1066 1067
static void
gtk_combo_box_button_state_changed (GtkWidget    *widget,
				    GtkStateType  previous,
				    gpointer      data)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
1068
  GtkComboBoxPrivate *priv = combo_box->priv;
1069 1070 1071

  if (GTK_WIDGET_REALIZED (widget))
    {
1072
      if (!priv->tree_view && priv->cell_view)
1073 1074
	{
	  if ((GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE) !=
1075 1076
	      (GTK_WIDGET_STATE (priv->cell_view) == GTK_STATE_INSENSITIVE))
	    gtk_widget_set_sensitive (priv->cell_view, GTK_WIDGET_SENSITIVE (widget));
1077
	  
1078
	  gtk_widget_set_state (priv->cell_view, 
1079 1080
				GTK_WIDGET_STATE (widget));
	}
1081 1082 1083 1084 1085
    }

  gtk_widget_queue_draw (widget);
}

1086
static void
1087
gtk_combo_box_check_appearance (GtkComboBox *combo_box)
1088
{
1089
  GtkComboBoxPrivate *priv = combo_box->priv;
1090
  gboolean appears_as_list;
1091 1092 1093 1094

  /* if wrap_width > 0, then we are in grid-mode and forced to use
   * unix style
   */
1095
  if (priv->wrap_width)
1096 1097 1098 1099 1100
    appears_as_list = FALSE;
  else
    gtk_widget_style_get (GTK_WIDGET (combo_box),
			  "appears-as-list", &appears_as_list,
			  NULL);
1101

1102
  if (appears_as_list)
1103
    {
1104
      /* Destroy all the menu mode widgets, if they exist. */
1105
      if (GTK_IS_MENU (priv->popup_widget))
1106 1107 1108
	gtk_combo_box_menu_destroy (combo_box);

      /* Create the list mode widgets, if they don't already exist. */
1109
      if (!GTK_IS_TREE_VIEW (priv->tree_view))
1110
	gtk_combo_box_list_setup (combo_box);
1111 1112 1113
    }
  else
    {
1114
      /* Destroy all the list mode widgets, if they exist. */
1115
      if (GTK_IS_TREE_VIEW (priv->tree_view))
1116 1117 1118
	gtk_combo_box_list_destroy (combo_box);

      /* Create the menu mode widgets, if they don't already exist. */
1119
      if (!GTK_IS_MENU (priv->popup_widget))
1120
	gtk_combo_box_menu_setup (combo_box, TRUE);
1121
    }
1122 1123

  gtk_widget_style_get (GTK_WIDGET (combo_box),
1124
			"shadow-type", &priv->shadow_type,
1125
			NULL);
1126 1127 1128 1129 1130 1131 1132
}

static void
gtk_combo_box_style_set (GtkWidget *widget,
                         GtkStyle  *previous)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
1133
  GtkComboBoxPrivate *priv = combo_box->priv;
1134 1135

  gtk_combo_box_check_appearance (combo_box);
1136

1137 1138
  if (priv->tree_view && priv->cell_view)
    gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), 
1139
					&widget->style->base[GTK_WIDGET_STATE (widget)]);
1140 1141 1142

  if (GTK_IS_ENTRY (GTK_BIN (combo_box)->child))
    g_object_set (GTK_BIN (combo_box)->child, "shadow-type",
1143
                  GTK_SHADOW_NONE == priv->shadow_type ?
1144
                  GTK_SHADOW_IN : GTK_SHADOW_NONE, NULL);
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
}

static void
gtk_combo_box_button_toggled (GtkWidget *widget,
                              gpointer   data)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (data);

  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
    {
      if (!combo_box->priv->popup_in_progress)
        gtk_combo_box_popup (combo_box);
    }
  else
    gtk_combo_box_popdown (combo_box);
}

static void
gtk_combo_box_add (GtkContainer *container,
                   GtkWidget    *widget)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1167
  GtkComboBoxPrivate *priv = combo_box->priv;
1168

1169
  if (priv->cell_view && priv->cell_view->parent)
1170
    {
1171
      gtk_widget_unparent (priv->cell_view);
1172 1173 1174 1175 1176 1177
      GTK_BIN (container)->child = NULL;
      gtk_widget_queue_resize (GTK_WIDGET (container));
    }
  
  gtk_widget_set_parent (widget, GTK_WIDGET (container));
  GTK_BIN (container)->child = widget;
1178

1179 1180
  if (priv->cell_view &&
      widget != priv->cell_view)
1181 1182
    {
      /* since the cell_view was unparented, it's gone now */
1183
      priv->cell_view = NULL;
1184

1185
      if (!priv->tree_view && priv->separator)
1186
        {
1187 1188 1189
	  gtk_container_remove (GTK_CONTAINER (priv->separator->parent),
				priv->separator);
	  priv->separator = NULL;
1190 1191 1192

          gtk_widget_queue_resize (GTK_WIDGET (container));
        }
1193
      else if (priv->cell_view_frame)
1194
        {
1195 1196 1197
          gtk_widget_unparent (priv->cell_view_frame);
          priv->cell_view_frame = NULL;
          priv->box = NULL;
1198 1199 1200 1201
        }
    }
}

1202 1203 1204 1205 1206
static void
gtk_combo_box_remove (GtkContainer *container,
		      GtkWidget    *widget)
{
  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
1207
  GtkComboBoxPrivate *priv = combo_box->priv;
1208
  GtkTreePath *path;
1209 1210
  gboolean appears_as_list;

1211 1212
  if (widget == priv->cell_view)
    priv->cell_view = NULL;
1213

1214 1215 1216
  gtk_widget_unparent (widget);
  GTK_BIN (container)->child = NULL;

1217
  if (GTK_OBJECT_FLAGS (combo_box) & GTK_IN_DESTRUCTION)
1218 1219 1220 1221
    return;

  gtk_widget_queue_resize (GTK_WIDGET (container));

1222
  if (!priv->tree_view)
1223 1224 1225 1226 1227 1228
    appears_as_list = FALSE;
  else
    appears_as_list = TRUE;
  
  if (appears_as_list)
    gtk_combo_box_list_destroy (combo_box);
1229
  else if (GTK_IS_MENU (priv->popup_widget))
1230 1231
    {
      gtk_combo_box_menu_destroy (combo_box);
1232 1233
      gtk_menu_detach (GTK_MENU (priv->popup_widget));
      priv->popup_widget = NULL;
1234 1235
    }

1236
  if (!priv->cell_view)
1237
    {
1238 1239 1240
      priv->cell_view = gtk_cell_view_new ();
      gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (container));
      GTK_BIN (container)->child = priv->cell_view;
1241
      
1242 1243 1244 1245
      gtk_widget_show (priv->cell_view);
      gtk_cell_view_set_model (GTK_CELL_VIEW (priv->cell_view),
			       priv->model);
      gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (priv->cell_view));
1246 1247 1248 1249
    }


  if (appears_as_list)
1250
    gtk_combo_box_list_setup (combo_box); 
1251 1252 1253
  else
    gtk_combo_box_menu_setup (combo_box, TRUE);

1254
  if (gtk_tree_row_reference_valid (priv->active_row))
1255
    {
1256
      path = gtk_tree_row_reference_get_path (priv->active_row);
1257 1258 1259