gtktreeview.c 215 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* gtktreeview.c
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 *
 * 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include "gtktreeview.h"
#include "gtkrbtree.h"
Havoc Pennington's avatar
Havoc Pennington committed
23
#include "gtktreednd.h"
24 25 26 27 28 29 30
#include "gtktreeprivate.h"
#include "gtkcellrenderer.h"
#include "gtksignal.h"
#include "gtkmain.h"
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
Havoc Pennington's avatar
Havoc Pennington committed
31 32
#include "gtkhbox.h"
#include "gtkarrow.h"
33
#include "gtkintl.h"
34 35 36

#include <gdk/gdkkeysyms.h>

Jonathan Blandford's avatar
Jonathan Blandford committed
37 38 39 40 41 42 43 44 45 46
#if defined (GDK_WINDOWING_X11)
#include "x11/gdkx.h"
#elif defined (GDK_WINDOWING_WIN32)
#include "win32/gdkwin32.h"
#elif defined(GDK_WINDOWING_FB)
#include "linux-fb/gdkfb.h"
#elif defined (GDK_WINDOWING_NANOX)
#include "nanox/gdkprivate-nanox.h"
#endif

47

48
#define SCROLL_EDGE_SIZE 15
49 50


Havoc Pennington's avatar
Havoc Pennington committed
51 52 53 54 55 56
/* The "background" areas of all rows/cells add up to cover the entire tree.
 * The background includes all inter-row and inter-cell spacing.
 * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
 * i.e. just the cells, no spacing.
 */
#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (_gtk_rbtree_node_find_offset ((tree), (node)) + TREE_VIEW_HEADER_HEIGHT ((tree_view)))
57
#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
Havoc Pennington's avatar
Havoc Pennington committed
58 59

#define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
60
#define CELL_HEIGHT(node, separator) (BACKGROUND_HEIGHT (node) - separator);
Havoc Pennington's avatar
Havoc Pennington committed
61 62 63

#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view))
#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view))
64 65


66
typedef struct _GtkTreeViewChild GtkTreeViewChild;
67 68 69 70 71 72 73
struct _GtkTreeViewChild
{
  GtkWidget *widget;
  gint x;
  gint y;
};

Jonathan Blandford's avatar
Jonathan Blandford committed
74

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
typedef struct _TreeViewDragInfo TreeViewDragInfo;
struct _TreeViewDragInfo
{
  GdkModifierType start_button_mask;
  GtkTargetList *source_target_list;
  GdkDragAction source_actions;
  GClosure *row_draggable_closure;

  GtkTargetList *dest_target_list;
  GClosure *location_droppable_closure;

  guint source_set : 1;
  guint dest_set : 1;
};


/* Signals */
92 93 94
enum
{
  ROW_ACTIVATED,
95 96
  EXPAND_ROW,
  COLLAPSE_ROW,
97
  COLUMNS_CHANGED,
98 99 100
  LAST_SIGNAL
};

101
/* Properties */
102 103 104 105 106 107 108 109
enum {
  PROP_0,
  PROP_MODEL,
  PROP_HADJUSTMENT,
  PROP_VADJUSTMENT,
  PROP_HEADERS_VISIBLE,
  PROP_HEADERS_CLICKABLE,
  PROP_EXPANDER_COLUMN,
110
  PROP_REORDERABLE,
111 112
  PROP_RULES_HINT
};
113 114

static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
115 116 117 118
static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);

/* object signals */
static void     gtk_tree_view_finalize             (GObject          *object);
119 120 121
static void     gtk_tree_view_set_property         (GObject         *object,
						    guint            prop_id,
						    const GValue    *value,
Jonathan Blandford's avatar
Jonathan Blandford committed
122
						    GParamSpec      *pspec);
123 124 125
static void     gtk_tree_view_get_property         (GObject         *object,
						    guint            prop_id,
						    GValue          *value,
Jonathan Blandford's avatar
Jonathan Blandford committed
126
						    GParamSpec      *pspec);
127

128
/* gtkobject signals */
Jonathan Blandford's avatar
Jonathan Blandford committed
129 130
static void     gtk_tree_view_destroy              (GtkObject        *object);

131
/* gtkwidget signals */
132
static void     gtk_tree_view_setup_model          (GtkTreeView      *tree_view);
133 134 135 136 137 138 139 140 141
static void     gtk_tree_view_realize              (GtkWidget        *widget);
static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
static void     gtk_tree_view_map                  (GtkWidget        *widget);
static void     gtk_tree_view_size_request         (GtkWidget        *widget,
						    GtkRequisition   *requisition);
static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
						    GtkAllocation    *allocation);
static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
						    GdkEventExpose   *event);
142 143
static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
						    GdkEventKey      *event);
144 145 146 147 148 149 150 151 152 153
static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
						    GdkEventMotion   *event);
static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
						    GdkEventCrossing *event);
static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
						    GdkEventCrossing *event);
static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
						    GdkEventButton   *event);
static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
						    GdkEventButton   *event);
154 155
static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
						    GtkWidget        *child);
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
static void     gtk_tree_view_draw_focus           (GtkWidget        *widget);
static gint     gtk_tree_view_focus_in             (GtkWidget        *widget,
						    GdkEventFocus    *event);
static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
						    GdkEventFocus    *event);
static gint     gtk_tree_view_focus                (GtkContainer     *container,
						    GtkDirectionType  direction);

/* container signals */
static void     gtk_tree_view_remove               (GtkContainer     *container,
						    GtkWidget        *widget);
static void     gtk_tree_view_forall               (GtkContainer     *container,
						    gboolean          include_internals,
						    GtkCallback       callback,
						    gpointer          callback_data);

Havoc Pennington's avatar
Havoc Pennington committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
/* Source side drag signals */
static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
                                            GdkDragContext   *context);
static void gtk_tree_view_drag_end         (GtkWidget        *widget,
                                            GdkDragContext   *context);
static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
                                            GdkDragContext   *context,
                                            GtkSelectionData *selection_data,
                                            guint             info,
                                            guint             time);
static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
                                            GdkDragContext   *context);

/* Target side drag signals */
static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  guint             time);
static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  guint             time);
static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  guint             time);
static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  GtkSelectionData *selection_data,
                                                  guint             info,
                                                  guint             time);

207 208 209 210
/* tree_model signals */
static void     gtk_tree_view_set_adjustments      (GtkTreeView      *tree_view,
						    GtkAdjustment    *hadj,
						    GtkAdjustment    *vadj);
211
static void     gtk_tree_view_range_changed        (GtkTreeModel     *model,
212
						    GtkTreePath      *path,
213
						    GtkTreeIter      *iter,
214 215
						    GtkTreePath      *end_path,
						    GtkTreeIter      *end_iter,
216
						    gpointer          data);
217
static void     gtk_tree_view_inserted             (GtkTreeModel     *model,
218
						    GtkTreePath      *path,
219
						    GtkTreeIter      *iter,
220
						    gpointer          data);
221
static void     gtk_tree_view_has_child_toggled    (GtkTreeModel     *model,
222
						    GtkTreePath      *path,
223
						    GtkTreeIter      *iter,
224
						    gpointer          data);
225
static void     gtk_tree_view_deleted              (GtkTreeModel     *model,
226 227
						    GtkTreePath      *path,
						    gpointer          data);
228 229
static void     gtk_tree_view_reordered            (GtkTreeModel     *model,
						    GtkTreePath      *parent,
230 231 232
						    GtkTreeIter      *iter,
						    gint             *new_order,
						    gpointer          data);
233
/* Internal functions */
234 235
static void     gtk_tree_view_unref_tree           (GtkTreeView      *tree_view,
						    GtkRBTree        *tree);
236 237 238 239
static void     gtk_tree_view_queue_draw_node      (GtkTreeView      *tree_view,
						    GtkRBTree        *tree,
						    GtkRBNode        *node,
						    GdkRectangle     *clip_rect);
Havoc Pennington's avatar
Havoc Pennington committed
240 241 242
static void     gtk_tree_view_queue_draw_path      (GtkTreeView      *tree_view,
                                                    GtkTreePath      *path,
                                                    GdkRectangle     *clip_rect);
243
static void     gtk_tree_view_draw_arrow           (GtkTreeView      *tree_view,
Havoc Pennington's avatar
Havoc Pennington committed
244
                                                    GtkRBTree        *tree,
245 246 247
						    GtkRBNode        *node,
						    gint              x,
						    gint              y);
Havoc Pennington's avatar
Havoc Pennington committed
248 249
static void     gtk_tree_view_get_arrow_xrange     (GtkTreeView      *tree_view,
                                                    gint              *x1,
Havoc Pennington's avatar
Havoc Pennington committed
250
                                                    gint              *x2);
251 252 253
static gint     gtk_tree_view_new_column_width     (GtkTreeView      *tree_view,
						    gint              i,
						    gint             *x);
254 255
static void     gtk_tree_view_ensure_scroll_timeout(GtkTreeView      *tree_view,
						    GFunc             func);
256 257
static void     gtk_tree_view_adjustment_changed   (GtkAdjustment    *adjustment,
						    GtkTreeView      *tree_view);
258
static gint     gtk_tree_view_insert_iter_height   (GtkTreeView      *tree_view,
259
						    GtkRBTree        *tree,
260
						    GtkTreeIter      *iter,
261 262 263
						    gint              depth);
static void     gtk_tree_view_build_tree           (GtkTreeView      *tree_view,
						    GtkRBTree        *tree,
264
						    GtkTreeIter      *iter,
265 266 267 268 269
						    gint              depth,
						    gboolean          recurse,
						    gboolean          calc_bounds);
static void     gtk_tree_view_calc_size            (GtkTreeView      *priv,
						    GtkRBTree        *tree,
270
						    GtkTreeIter      *iter,
271
						    gint              depth);
272 273
static gboolean gtk_tree_view_discover_dirty_iter  (GtkTreeView      *tree_view,
						    GtkTreeIter      *iter,
274 275 276 277
						    gint              depth,
						    gint             *height);
static void     gtk_tree_view_discover_dirty       (GtkTreeView      *tree_view,
						    GtkRBTree        *tree,
278
						    GtkTreeIter      *iter,
279 280 281 282 283
						    gint              depth);
static void     gtk_tree_view_check_dirty          (GtkTreeView      *tree_view);
static void     gtk_tree_view_clamp_node_visible   (GtkTreeView      *tree_view,
						    GtkRBTree        *tree,
						    GtkRBNode        *node);
Havoc Pennington's avatar
Havoc Pennington committed
284 285
static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
                                                        GdkEventMotion   *event);
286
static void     _gtk_tree_view_update_col_width    (GtkTreeView      *tree_view);
287

288 289

static GtkContainerClass *parent_class = NULL;
290
static guint tree_view_signals[LAST_SIGNAL] = { 0 };
291

292 293 294 295 296


/* GType Methods
 */

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
GtkType
gtk_tree_view_get_type (void)
{
  static GtkType tree_view_type = 0;

  if (!tree_view_type)
    {
      static const GTypeInfo tree_view_info =
      {
        sizeof (GtkTreeViewClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_tree_view_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkTreeView),
	0,              /* n_preallocs */
        (GInstanceInitFunc) gtk_tree_view_init
      };

317
      tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
318 319 320 321 322 323 324 325
    }

  return tree_view_type;
}

static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
{
326
  GObjectClass *o_class;
327 328 329 330
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

331 332
  parent_class = g_type_class_peek_parent (class);

333 334 335 336 337
  o_class = (GObjectClass *) class;
  object_class = (GtkObjectClass *) class;
  widget_class = (GtkWidgetClass *) class;
  container_class = (GtkContainerClass *) class;

338
  /* GObject signals */
339 340
  o_class->set_property = gtk_tree_view_set_property;
  o_class->get_property = gtk_tree_view_get_property;
341
  o_class->finalize = gtk_tree_view_finalize;
342

343
  /* GtkObject signals */
Jonathan Blandford's avatar
Jonathan Blandford committed
344
  object_class->destroy = gtk_tree_view_destroy;
345

346 347
  /* GtkWidget signals */
  widget_class->map = gtk_tree_view_map;
348 349 350 351
  widget_class->realize = gtk_tree_view_realize;
  widget_class->unrealize = gtk_tree_view_unrealize;
  widget_class->size_request = gtk_tree_view_size_request;
  widget_class->size_allocate = gtk_tree_view_size_allocate;
352 353
  widget_class->button_press_event = gtk_tree_view_button_press;
  widget_class->button_release_event = gtk_tree_view_button_release;
354
  widget_class->motion_notify_event = gtk_tree_view_motion;
355
  widget_class->expose_event = gtk_tree_view_expose;
356
  widget_class->key_press_event = gtk_tree_view_key_press;
357 358 359 360
  widget_class->enter_notify_event = gtk_tree_view_enter_notify;
  widget_class->leave_notify_event = gtk_tree_view_leave_notify;
  widget_class->focus_in_event = gtk_tree_view_focus_in;
  widget_class->focus_out_event = gtk_tree_view_focus_out;
Havoc Pennington's avatar
Havoc Pennington committed
361 362 363 364 365 366 367 368
  widget_class->drag_begin = gtk_tree_view_drag_begin;
  widget_class->drag_end = gtk_tree_view_drag_end;
  widget_class->drag_data_get = gtk_tree_view_drag_data_get;
  widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
  widget_class->drag_leave = gtk_tree_view_drag_leave;
  widget_class->drag_motion = gtk_tree_view_drag_motion;
  widget_class->drag_drop = gtk_tree_view_drag_drop;
  widget_class->drag_data_received = gtk_tree_view_drag_data_received;
Jonathan Blandford's avatar
Jonathan Blandford committed
369

370
  /* GtkContainer signals */
371
  container_class->remove = gtk_tree_view_remove;
372
  container_class->forall = gtk_tree_view_forall;
373
  container_class->focus = gtk_tree_view_focus;
374
  container_class->set_focus_child = gtk_tree_view_set_focus_child;
375 376 377

  class->set_scroll_adjustments = gtk_tree_view_set_adjustments;

378 379
  g_object_class_install_property (o_class,
                                   PROP_MODEL,
Tim Janik's avatar
Tim Janik committed
380 381 382 383 384
                                   g_param_spec_object ("model",
							_("TreeView Model"),
							_("The model for the tree view"),
							GTK_TYPE_TREE_MODEL,
							G_PARAM_READWRITE));
Jonathan Blandford's avatar
Jonathan Blandford committed
385

386 387 388 389
  g_object_class_install_property (o_class,
                                   PROP_HADJUSTMENT,
                                   g_param_spec_object ("hadjustment",
							_("Horizontal Adjustment"),
Jonathan Blandford's avatar
Jonathan Blandford committed
390
                                                        _("Horizontal Adjustment for the widget"),
391 392 393 394 395 396 397
                                                        GTK_TYPE_ADJUSTMENT,
                                                        G_PARAM_READWRITE));

  g_object_class_install_property (o_class,
                                   PROP_VADJUSTMENT,
                                   g_param_spec_object ("vadjustment",
							_("Vertical Adjustment"),
Jonathan Blandford's avatar
Jonathan Blandford committed
398
                                                        _("Vertical Adjustment for the widget"),
399 400 401 402 403 404 405
                                                        GTK_TYPE_ADJUSTMENT,
                                                        G_PARAM_READWRITE));

  g_object_class_install_property (o_class,
                                   PROP_HEADERS_VISIBLE,
                                   g_param_spec_boolean ("headers_visible",
							 _("Visible"),
Jonathan Blandford's avatar
Jonathan Blandford committed
406
							 _("Show the column header buttons"),
407 408 409 410 411 412 413
							 FALSE,
							 G_PARAM_READWRITE));

  g_object_class_install_property (o_class,
                                   PROP_HEADERS_CLICKABLE,
                                   g_param_spec_boolean ("headers_clickable",
							 _("Headers Clickable"),
Jonathan Blandford's avatar
Jonathan Blandford committed
414
							 _("Column headers respond to click events"),
415
							 FALSE,
416
							 G_PARAM_WRITABLE));
417 418 419 420 421 422 423 424 425 426 427

  g_object_class_install_property (o_class,
                                   PROP_EXPANDER_COLUMN,
                                   g_param_spec_uint ("expander_column",
						      _("Expand Column"),
						      _("Set the column number for the expander column"),
						      0,
						      G_MAXINT,
						      0,
						      G_PARAM_READWRITE));

428 429 430 431 432 433 434 435
  g_object_class_install_property (o_class,
                                   PROP_REORDERABLE,
                                   g_param_spec_boolean ("reorderable",
							 _("Reorderable"),
							 _("View is reorderable"),
							 FALSE,
							 G_PARAM_READWRITE));

436 437 438 439
  g_object_class_install_property (o_class,
                                   PROP_RULES_HINT,
                                   g_param_spec_boolean ("rules_hint",
							 _("Rules Hint"),
Jonathan Blandford's avatar
Jonathan Blandford committed
440
							 _("Set a hint to the theme engine to draw rows in alternating colors"),
441 442 443
							 FALSE,
							 G_PARAM_READWRITE));

444 445 446 447 448
  widget_class->set_scroll_adjustments_signal =
    gtk_signal_new ("set_scroll_adjustments",
		    GTK_RUN_LAST,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
Tim Janik's avatar
Tim Janik committed
449
		    gtk_marshal_VOID__OBJECT_OBJECT,
450
		    GTK_TYPE_NONE, 2,
451
		    GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
452

453 454 455 456 457 458 459 460 461
  tree_view_signals[ROW_ACTIVATED] =
    gtk_signal_new ("row_activated",
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
		    gtk_marshal_VOID__BOXED_OBJECT,
		    GTK_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_VIEW_COLUMN);
462

463 464 465 466 467 468 469 470 471 472
  tree_view_signals[EXPAND_ROW] =
    g_signal_newc ("expand_row",
		   G_TYPE_FROM_CLASS (object_class),
		   G_SIGNAL_RUN_LAST,
		   G_STRUCT_OFFSET (GtkTreeViewClass, expand_row),
		   _gtk_boolean_handled_accumulator, NULL,
		    gtk_marshal_BOOLEAN__BOXED_BOXED,
		   G_TYPE_BOOLEAN, 2,
		   GTK_TYPE_TREE_ITER,
		   GTK_TYPE_TREE_PATH);
473

474 475 476 477 478 479 480 481 482 483
  tree_view_signals[COLLAPSE_ROW] =
    g_signal_newc ("collapse_row",
		   G_TYPE_FROM_CLASS (object_class),
		   G_SIGNAL_RUN_LAST,
		   G_STRUCT_OFFSET (GtkTreeViewClass, collapse_row),
		   _gtk_boolean_handled_accumulator, NULL,
		    gtk_marshal_BOOLEAN__BOXED_BOXED,
		   G_TYPE_BOOLEAN, 2,
		   GTK_TYPE_TREE_ITER,
		   GTK_TYPE_TREE_PATH);
484

485 486 487 488 489 490 491 492 493
  tree_view_signals[COLUMNS_CHANGED] =
    g_signal_newc ("columns_changed",
		   G_TYPE_FROM_CLASS (object_class),
		   G_SIGNAL_RUN_LAST,
		   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
		   NULL, NULL,
		   gtk_marshal_NONE__NONE,
		   G_TYPE_NONE, 0);

494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
/* the width of the column resize windows */
#define _TREE_VIEW_EXPANDER_WIDTH 14
#define _TREE_VIEW_EXPANDER_HEIGHT 14
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
#define _TREE_VIEW_HORIZONTAL_SEPARATOR 0

  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("expander_width",
							     _("Expander Width"),
							     _("Width of the expander arrow"),
							     0,
							     G_MAXINT,
							     _TREE_VIEW_EXPANDER_WIDTH,
							     G_PARAM_READABLE));

  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("expander_height",
							     _("Expander Height"),
							     _("Height of the expander arrow"),
							     4,
							     G_MAXINT,
							     _TREE_VIEW_EXPANDER_HEIGHT,
							     G_PARAM_READABLE));

    gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("vertical_separator",
							     _("Vertical Separator Width"),
							     _("Vertical space between cells"),
							     0,
							     G_MAXINT,
							     _TREE_VIEW_VERTICAL_SEPARATOR,
							     G_PARAM_READABLE));

    gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("horizontal_separator",
							     _("Horizontal Separator Width"),
							     _("Horizontal space between cells"),
							     0,
							     G_MAXINT,
							     _TREE_VIEW_HORIZONTAL_SEPARATOR,
							     G_PARAM_READABLE));
535 536 537 538 539 540 541 542 543 544
}

static void
gtk_tree_view_init (GtkTreeView *tree_view)
{
  tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);

  GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);

  tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
545
  gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_width", &tree_view->priv->tab_offset, NULL);
546
  tree_view->priv->n_columns = 0;
547 548 549
  tree_view->priv->header_height = 1;
  tree_view->priv->x_drag = 0;
  tree_view->priv->drag_pos = -1;
550
  tree_view->priv->header_has_focus = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
551 552 553
  tree_view->priv->pressed_button = -1;
  tree_view->priv->press_start_x = -1;
  tree_view->priv->press_start_y = -1;
554
  tree_view->priv->reorderable = FALSE;
555
  gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
556
  _gtk_tree_view_update_size (tree_view);
557 558
}

559

560

561
/* GObject Methods
562 563
 */

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
static void
gtk_tree_view_set_property (GObject         *object,
			    guint            prop_id,
			    const GValue    *value,
			    GParamSpec      *pspec)
{
  GtkTreeView *tree_view;

  tree_view = GTK_TREE_VIEW (object);

  switch (prop_id)
    {
    case PROP_MODEL:
      gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (g_value_get_object (value)));
      break;
    case PROP_HADJUSTMENT:
      gtk_tree_view_set_hadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
      break;
    case PROP_VADJUSTMENT:
      gtk_tree_view_set_vadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
      break;
    case PROP_HEADERS_VISIBLE:
      gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
      break;
    case PROP_HEADERS_CLICKABLE:
      gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
      break;
    case PROP_EXPANDER_COLUMN:
      gtk_tree_view_set_expander_column (tree_view, g_value_get_uint (value));
      break;
594 595 596
    case PROP_REORDERABLE:
      gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
      break;
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
    case PROP_RULES_HINT:
      gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
      break;
    default:
      break;
    }
}

static void
gtk_tree_view_get_property (GObject         *object,
			    guint            prop_id,
			    GValue          *value,
			    GParamSpec      *pspec)
{
  GtkTreeView *tree_view;

  tree_view = GTK_TREE_VIEW (object);

  switch (prop_id)
    {
    case PROP_MODEL:
      g_value_set_object (value, G_OBJECT (tree_view->priv->model));
      break;
    case PROP_HADJUSTMENT:
      g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
      break;
    case PROP_VADJUSTMENT:
      g_value_set_object (value, G_OBJECT (tree_view->priv->vadjustment));
      break;
    case PROP_HEADERS_VISIBLE:
      g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
      break;
    case PROP_EXPANDER_COLUMN:
      g_value_set_uint (value, tree_view->priv->expander_column);
      break;
632 633 634
    case PROP_REORDERABLE:
      g_value_set_boolean (value, tree_view->priv->reorderable);
      break;
635 636 637 638 639 640 641 642 643
    case PROP_RULES_HINT:
      g_value_set_boolean (value, tree_view->priv->has_rules);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

644 645 646 647 648 649
static void
gtk_tree_view_finalize (GObject *object)
{
  GtkTreeView *tree_view = (GtkTreeView *) object;

  g_free (tree_view->priv);
650

651 652 653 654
  if (G_OBJECT_CLASS (parent_class)->finalize)
    (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}

655 656 657 658 659


/* GtkObject Methods
 */

Jonathan Blandford's avatar
Jonathan Blandford committed
660 661 662 663 664 665 666
static void
gtk_tree_view_destroy (GtkObject *object)
{
  GtkTreeView *tree_view = (GtkTreeView *) object;
  GList *list;


667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
  if (tree_view->priv->tree != NULL)
    {
      gtk_tree_view_unref_tree (tree_view, tree_view->priv->tree);
      _gtk_rbtree_free (tree_view->priv->tree);
      tree_view->priv->tree = NULL;
    }

  if (tree_view->priv->model != NULL)
    {
      g_object_unref (G_OBJECT (tree_view->priv->model));
      tree_view->priv->model = NULL;
    }

  if (tree_view->priv->columns != NULL)
    {
      for (list = tree_view->priv->columns; list; list = list->next)
	g_object_unref (G_OBJECT (list->data));
      g_list_free (tree_view->priv->columns);
      tree_view->priv->columns = NULL;
    }

  if (tree_view->priv->selection != NULL)
    {
      _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
      g_object_unref (tree_view->priv->selection);
      tree_view->priv->selection = NULL;
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
694

695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
  if (tree_view->priv->anchor != NULL)
    {
      gtk_tree_row_reference_free (tree_view->priv->anchor);
      tree_view->priv->anchor = NULL;
    }

  if (tree_view->priv->scroll_to_path != NULL)
    {
      gtk_tree_path_free (tree_view->priv->scroll_to_path);
      tree_view->priv->scroll_to_path = NULL;
    }

  if (tree_view->priv->drag_dest_row != NULL)
    {
      gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
      tree_view->priv->drag_dest_row = NULL;
    }

  if (tree_view->priv->cursor)
    {
      gtk_tree_row_reference_free (tree_view->priv->cursor);
      tree_view->priv->cursor = NULL;
    }

719 720 721 722 723 724 725
  if (tree_view->priv->column_drop_func_data &&
      tree_view->priv->column_drop_func_data_destroy)
    {
      (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
      tree_view->priv->column_drop_func_data = NULL;
    }

726 727
  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
Jonathan Blandford's avatar
Jonathan Blandford committed
728 729
}

730 731 732


/* GtkWidget Methods
733 734
 */

735
/* GtkWidget::map helper */
736
static void
737
gtk_tree_view_map_buttons (GtkTreeView *tree_view)
738
{
739
  GList *list;
740

741
  g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
742

743
  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
744
    {
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
      GtkTreeViewColumn *column;

      for (list = tree_view->priv->columns; list; list = list->next)
	{
	  column = list->data;
          if (GTK_WIDGET_VISIBLE (column->button) &&
              !GTK_WIDGET_MAPPED (column->button))
            gtk_widget_map (column->button);
	}
      for (list = tree_view->priv->columns; list; list = list->next)
	{
	  column = list->data;
	  if (column->visible == FALSE)
	    continue;
	  if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
	    {
	      gdk_window_raise (column->window);
	      gdk_window_show (column->window);
	    }
	  else
	    gdk_window_hide (column->window);
	}
      gdk_window_show (tree_view->priv->header_window);
768 769 770 771
    }
}

static void
772
gtk_tree_view_map (GtkWidget *widget)
773
{
774
  GList *tmp_list;
775 776
  GtkTreeView *tree_view;

777
  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
Jonathan Blandford's avatar
Jonathan Blandford committed
778

779 780 781 782 783 784
  tree_view = GTK_TREE_VIEW (widget);

  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);

  tmp_list = tree_view->priv->children;
  while (tmp_list)
785
    {
786 787 788 789 790 791 792 793
      GtkTreeViewChild *child = tmp_list->data;
      tmp_list = tmp_list->next;

      if (GTK_WIDGET_VISIBLE (child->widget))
	{
	  if (!GTK_WIDGET_MAPPED (child->widget))
	    gtk_widget_map (child->widget);
	}
794
    }
795
  gdk_window_show (tree_view->priv->bin_window);
796

797 798 799 800
  gtk_tree_view_map_buttons (tree_view);

  gdk_window_show (widget->window);
}
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894

static void
gtk_tree_view_realize (GtkWidget *widget)
{
  GList *tmp_list;
  GtkTreeView *tree_view;
  GdkGCValues values;
  GdkWindowAttr attributes;
  gint attributes_mask;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_TREE_VIEW (widget));

  tree_view = GTK_TREE_VIEW (widget);

  gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);

  /* Make the main, clipping window */
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.x = widget->allocation.x;
  attributes.y = widget->allocation.y;
  attributes.width = widget->allocation.width;
  attributes.height = widget->allocation.height;
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.colormap = gtk_widget_get_colormap (widget);
  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;

  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;

  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
				   &attributes, attributes_mask);
  gdk_window_set_user_data (widget->window, widget);

  /* Make the window for the tree */
  attributes.x = 0;
  attributes.y = 0;
  attributes.width = tree_view->priv->width;
  attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
  attributes.event_mask = GDK_EXPOSURE_MASK |
    GDK_SCROLL_MASK |
    GDK_POINTER_MOTION_MASK |
    GDK_ENTER_NOTIFY_MASK |
    GDK_LEAVE_NOTIFY_MASK |
    GDK_BUTTON_PRESS_MASK |
    GDK_BUTTON_RELEASE_MASK |
    gtk_widget_get_events (widget);

  tree_view->priv->bin_window = gdk_window_new (widget->window,
						&attributes, attributes_mask);
  gdk_window_set_user_data (tree_view->priv->bin_window, widget);

  /* Make the column header window */
  attributes.x = 0;
  attributes.y = 0;
  attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
  attributes.height = tree_view->priv->header_height;
  attributes.event_mask = (GDK_EXPOSURE_MASK |
			   GDK_SCROLL_MASK |
			   GDK_BUTTON_PRESS_MASK |
			   GDK_BUTTON_RELEASE_MASK |
			   GDK_KEY_PRESS_MASK |
			   GDK_KEY_RELEASE_MASK) |
    gtk_widget_get_events (widget);

  tree_view->priv->header_window = gdk_window_new (widget->window,
						   &attributes, attributes_mask);
  gdk_window_set_user_data (tree_view->priv->header_window, widget);


  values.foreground = (widget->style->white.pixel==0 ?
		       widget->style->black:widget->style->white);
  values.function = GDK_XOR;
  values.subwindow_mode = GDK_INCLUDE_INFERIORS;
  tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
						    &values,
						    GDK_GC_FOREGROUND |
						    GDK_GC_FUNCTION |
						    GDK_GC_SUBWINDOW);
  /* Add them all up. */
  widget->style = gtk_style_attach (widget->style, widget->window);
  gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
  gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
  gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);

  tmp_list = tree_view->priv->children;
  while (tmp_list)
    {
      GtkTreeViewChild *child = tmp_list->data;
      tmp_list = tmp_list->next;

      gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
    }
895 896 897 898

  for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
    _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));

899
  _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915

  if (tree_view->priv->scroll_to_path != NULL ||
      tree_view->priv->scroll_to_column != NULL)
    {
      gtk_tree_view_scroll_to_cell (tree_view,
				    tree_view->priv->scroll_to_path,
				    tree_view->priv->scroll_to_column,
				    tree_view->priv->scroll_to_row_align,
				    tree_view->priv->scroll_to_col_align);
      if (tree_view->priv->scroll_to_path)
	{
	  gtk_tree_path_free (tree_view->priv->scroll_to_path);
	  tree_view->priv->scroll_to_path = NULL;
	}
      tree_view->priv->scroll_to_column = NULL;
    }
916 917 918 919 920 921
}

static void
gtk_tree_view_unrealize (GtkWidget *widget)
{
  GtkTreeView *tree_view;
922
  GList *list;
923 924 925 926 927

  g_return_if_fail (GTK_IS_TREE_VIEW (widget));

  tree_view = GTK_TREE_VIEW (widget);

Havoc Pennington's avatar
Havoc Pennington committed
928 929 930 931 932 933 934 935 936 937 938
  if (tree_view->priv->scroll_timeout != 0)
    {
      gtk_timeout_remove (tree_view->priv->scroll_timeout);
      tree_view->priv->scroll_timeout = 0;
    }

  if (tree_view->priv->open_dest_timeout != 0)
    {
      gtk_timeout_remove (tree_view->priv->open_dest_timeout);
      tree_view->priv->open_dest_timeout = 0;
    }
939 940 941 942

  for (list = tree_view->priv->columns; list; list = list->next)
    _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));

943 944 945 946 947 948 949 950
  gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
  gdk_window_destroy (tree_view->priv->bin_window);
  tree_view->priv->bin_window = NULL;

  gdk_window_set_user_data (tree_view->priv->header_window, NULL);
  gdk_window_destroy (tree_view->priv->header_window);
  tree_view->priv->header_window = NULL;

951 952 953 954 955 956 957 958 959 960 961 962 963 964
  if (tree_view->priv->drag_window)
    {
      gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
      gdk_window_destroy (tree_view->priv->drag_window);
      tree_view->priv->drag_window = NULL;
    }

  if (tree_view->priv->drag_highlight_window)
    {
      gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
      gdk_window_destroy (tree_view->priv->drag_highlight_window);
      tree_view->priv->drag_highlight_window = NULL;
    }

965 966 967 968 969
  if (tree_view->priv->cursor_drag)
    {
      gdk_cursor_destroy (tree_view->priv->cursor_drag);
      tree_view->priv->cursor_drag = NULL;
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
970

971 972 973 974 975
  if (tree_view->priv->xor_gc)
    {
      gdk_gc_destroy (tree_view->priv->xor_gc);
      tree_view->priv->xor_gc = NULL;
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
976

977
  /* GtkWidget::unrealize destroys children and widget->window */
978 979 980 981
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}

982
/* GtkWidget::size_request helper */
983
static void
984
gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
985 986 987
{
  GList *list;

988
  tree_view->priv->header_height = 1;
Jonathan Blandford's avatar
Jonathan Blandford committed
989

990
  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
991
    {
992 993 994 995
      for (list = tree_view->priv->columns; list; list = list->next)
        {
          GtkRequisition requisition;
          GtkTreeViewColumn *column;
Jonathan Blandford's avatar
Jonathan Blandford committed
996

997
          column = list->data;
Jonathan Blandford's avatar
Jonathan Blandford committed
998

999
          gtk_widget_size_request (column->button, &requisition);
Jonathan Blandford's avatar
Jonathan Blandford committed
1000

1001
          _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
1002 1003
          tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
        }
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
    }
}

static void
gtk_tree_view_size_request (GtkWidget      *widget,
			    GtkRequisition *requisition)
{
  GtkTreeView *tree_view;
  GList *tmp_list;

  g_return_if_fail (GTK_IS_TREE_VIEW (widget));

  tree_view = GTK_TREE_VIEW (widget);

  requisition->width = 200;
  requisition->height = 200;

  tmp_list = tree_view->priv->children;

  while (tmp_list)
    {
      GtkTreeViewChild *child = tmp_list->data;
      GtkRequisition child_requisition;

      tmp_list = tmp_list->next;

1030 1031
      if (GTK_WIDGET_VISIBLE (child->widget))
        gtk_widget_size_request (child->widget, &child_requisition);
1032
    }
1033 1034

  gtk_tree_view_size_request_buttons (tree_view);
1035 1036
}

1037
/* GtkWidget::size_allocate helper */
1038 1039 1040 1041 1042 1043 1044 1045
static void
gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
{
  GtkTreeView *tree_view;
  GList *list;
  GtkTreeViewColumn *column;
  GtkAllocation allocation;
  gint width = 0;
Jonathan Blandford's avatar
Jonathan Blandford committed
1046

1047 1048 1049 1050 1051
  tree_view = GTK_TREE_VIEW (widget);

  allocation.y = 0;
  allocation.height = tree_view->priv->header_height;

1052
  for (list = tree_view->priv->columns; list != NULL; list = list->next)
1053 1054 1055 1056 1057 1058 1059
    {
      column = list->data;

      if (!column->visible)
	continue;

      allocation.x = width;
1060
      allocation.width = column->displayed_width;
Havoc Pennington's avatar
Havoc Pennington committed
1061
      width += column->width;
1062 1063 1064
      gtk_widget_size_allocate (column->button, &allocation);

      if (column->window)
1065
	gdk_window_move_resize (column->window,
1066 1067
                                allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
				allocation.y,
1068
                                TREE_VIEW_DRAG_WIDTH, allocation.height);
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    }
}

static void
gtk_tree_view_size_allocate (GtkWidget     *widget,
			     GtkAllocation *allocation)
{
  GList *tmp_list;
  GtkTreeView *tree_view;

  g_return_if_fail (GTK_IS_TREE_VIEW (widget));

  widget->allocation = *allocation;

  tree_view = GTK_TREE_VIEW (widget);
Jonathan Blandford's avatar
Jonathan Blandford committed
1084

Havoc Pennington's avatar
Havoc Pennington committed
1085
  gtk_tree_view_check_dirty (tree_view);
Jonathan Blandford's avatar
Jonathan Blandford committed
1086

1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
  tmp_list = tree_view->priv->children;

  while (tmp_list)
    {
      GtkAllocation allocation;
      GtkRequisition requisition;

      GtkTreeViewChild *child = tmp_list->data;
      tmp_list = tmp_list->next;

      allocation.x = child->x;
      allocation.y = child->y;
      gtk_widget_get_child_requisition (child->widget, &requisition);
      allocation.width = requisition.width;
      allocation.height = requisition.height;

      gtk_widget_size_allocate (child->widget, &allocation);
    }

  if (GTK_WIDGET_REALIZED (widget))
    {
      gdk_window_move_resize (widget->window,
			      allocation->x, allocation->y,
			      allocation->width, allocation->height);
1111 1112 1113
      gdk_window_resize (tree_view->priv->header_window,
			 MAX (tree_view->priv->width, allocation->width),
			 tree_view->priv->header_height);
1114
      if (tree_view->priv->width < allocation->width)
1115 1116 1117
	  gdk_window_resize (tree_view->priv->bin_window,
			     allocation->width,
			     tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
1118 1119

      _gtk_tree_view_update_col_width (tree_view);
1120
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
1121

1122 1123
  gtk_tree_view_size_allocate_buttons (widget);

1124 1125 1126 1127
  tree_view->priv->hadjustment->page_size = allocation->width;
  tree_view->priv->hadjustment->page_increment = allocation->width / 2;
  tree_view->priv->hadjustment->lower = 0;
  tree_view->priv->hadjustment->upper = tree_view->priv->width;
Havoc Pennington's avatar
Havoc Pennington committed
1128

1129 1130 1131 1132 1133 1134 1135 1136
  if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
    tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
  gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");

  tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
  tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
  tree_view->priv->vadjustment->lower = 0;
  tree_view->priv->vadjustment->upper = tree_view->priv->height;
Havoc Pennington's avatar
Havoc Pennington committed
1137

1138 1139
  if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
    gtk_adjustment_set_value (tree_view->priv->vadjustment,
1140
			      MAX (tree_view->priv->height - allocation->height, 0));
Havoc Pennington's avatar
Havoc Pennington committed
1141

1142
  gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
1143

1144 1145
}

1146 1147 1148
static gboolean
gtk_tree_view_button_press (GtkWidget      *widget,
			    GdkEventButton *event)
Havoc Pennington's avatar
Havoc Pennington committed
1149
{
1150
  GtkTreeView *tree_view;
Havoc Pennington's avatar
Havoc Pennington committed
1151
  GList *list;
1152 1153
  GtkTreeViewColumn *column = NULL;
  gint i;
Havoc Pennington's avatar
Havoc Pennington committed
1154
  GdkRectangle background_area;
1155 1156
  GdkRectangle cell_area;
  gint vertical_separator;
Jonathan Blandford's avatar
Jonathan Blandford committed
1157

1158 1159
  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);
Havoc Pennington's avatar
Havoc Pennington committed
1160

1161 1162
  tree_view = GTK_TREE_VIEW (widget);
  gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
Havoc Pennington's avatar
Havoc Pennington committed
1163

1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
  if (event->window == tree_view->priv->bin_window)
    {
      GtkRBNode *node;
      GtkRBTree *tree;
      GtkTreePath *path;
      gchar *path_string;
      gint depth;
      gint new_y;
      gint y_offset;
      GtkTreeViewColumn *column = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
1174

1175 1176 1177
      if (!GTK_WIDGET_HAS_FOCUS (widget))
	gtk_widget_grab_focus (widget);
      GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
Jonathan Blandford's avatar
Jonathan Blandford committed
1178

1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
      /* are we in an arrow? */
      if (tree_view->priv->prelight_node &&
          GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
	{
	  if (event->button == 1)
	    {
	      gtk_grab_add (widget);
	      tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
	      tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
	      gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
                                        tree_view->priv->prelight_tree,
					tree_view->priv->prelight_node,
					event->x,
					event->y);
	    }
	  return TRUE;
	}
Jonathan Blandford's avatar
Jonathan Blandford committed
1196

1197 1198 1199 1200 1201 1202
      /* find the node that was clicked */
      new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
      y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
                                           TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
					   &tree,
					   &node) + new_y - (gint)event->y;
Havoc Pennington's avatar
Havoc Pennington committed
1203

1204 1205 1206
      if (node == NULL)
	/* We clicked in dead space */
	return TRUE;
Havoc Pennington's avatar
Havoc Pennington committed
1207

1208 1209 1210 1211 1212 1213 1214
      /* Get the path and the node */
      path = _gtk_tree_view_find_path (tree_view, tree, node);
      depth = gtk_tree_path_get_depth (path);
      background_area.y = y_offset + event->y + vertical_separator;
      background_area.height = GTK_RBNODE_GET_HEIGHT (node) - vertical_separator;
      background_area.x = 0;
      /* Let the cell have a chance at selecting it. */
Jonathan Blandford's avatar
Jonathan Blandford committed
1215

1216 1217 1218 1219 1220 1221
      for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
	{
	  GtkCellRenderer *cell;
	  GtkTreeIter iter;
	  gboolean visible;
	  gboolean can_activate;
Havoc Pennington's avatar
Havoc Pennington committed
1222

1223
	  column = list->data;
Havoc Pennington's avatar
Havoc Pennington committed
1224

1225 1226
	  if (!column->visible)
	    continue;
Jonathan Blandford's avatar
Jonathan Blandford committed
1227