gtktreeview.c 201 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 98 99
  LAST_SIGNAL
};

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

static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
113 114 115 116
static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);

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

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

129
/* gtkwidget signals */
130
static void     gtk_tree_view_setup_model          (GtkTreeView      *tree_view);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
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);
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);
150 151
static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
						    GtkWidget        *child);
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
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
168 169 170 171 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
/* 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);

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

282 283

static GtkContainerClass *parent_class = NULL;
284
static guint tree_view_signals[LAST_SIGNAL] = { 0 };
285

286 287 288 289 290


/* GType Methods
 */

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
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
      };

311
      tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
312 313 314 315 316 317 318 319
    }

  return tree_view_type;
}

static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
{
320
  GObjectClass *o_class;
321 322 323 324
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

325 326
  parent_class = g_type_class_peek_parent (class);

327 328 329 330 331
  o_class = (GObjectClass *) class;
  object_class = (GtkObjectClass *) class;
  widget_class = (GtkWidgetClass *) class;
  container_class = (GtkContainerClass *) class;

332
  /* GObject signals */
333 334
  o_class->set_property = gtk_tree_view_set_property;
  o_class->get_property = gtk_tree_view_get_property;
335
  o_class->finalize = gtk_tree_view_finalize;
336

337
  /* GtkObject signals */
Jonathan Blandford's avatar
Jonathan Blandford committed
338
  object_class->destroy = gtk_tree_view_destroy;
339

340 341
  /* GtkWidget signals */
  widget_class->map = gtk_tree_view_map;
342 343 344 345
  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;
346 347
  widget_class->button_press_event = gtk_tree_view_button_press;
  widget_class->button_release_event = gtk_tree_view_button_release;
348
  widget_class->motion_notify_event = gtk_tree_view_motion;
349
  widget_class->expose_event = gtk_tree_view_expose;
350 351 352 353
  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
354 355 356 357 358 359 360 361
  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
362

363
  /* GtkContainer signals */
364
  container_class->remove = gtk_tree_view_remove;
365
  container_class->forall = gtk_tree_view_forall;
366
  container_class->focus = gtk_tree_view_focus;
367
  container_class->set_focus_child = gtk_tree_view_set_focus_child;
368 369 370

  class->set_scroll_adjustments = gtk_tree_view_set_adjustments;

371 372
  g_object_class_install_property (o_class,
                                   PROP_MODEL,
Tim Janik's avatar
Tim Janik committed
373 374 375 376 377
                                   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
378

379 380 381 382
  g_object_class_install_property (o_class,
                                   PROP_HADJUSTMENT,
                                   g_param_spec_object ("hadjustment",
							_("Horizontal Adjustment"),
Jonathan Blandford's avatar
Jonathan Blandford committed
383
                                                        _("Horizontal Adjustment for the widget"),
384 385 386 387 388 389 390
                                                        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
391
                                                        _("Vertical Adjustment for the widget"),
392 393 394 395 396 397 398
                                                        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
399
							 _("Show the column header buttons"),
400 401 402 403 404 405 406
							 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
407
							 _("Column headers respond to click events"),
408
							 FALSE,
409
							 G_PARAM_WRITE));
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424

  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));

  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
425
							 _("Set a hint to the theme engine to draw rows in alternating colors"),
426 427 428
							 FALSE,
							 G_PARAM_READWRITE));

429 430 431 432 433
  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
434
		    gtk_marshal_VOID__OBJECT_OBJECT,
435
		    GTK_TYPE_NONE, 2,
436
		    GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
437

438 439 440 441 442 443 444 445 446
  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);
447

448 449 450 451 452 453 454 455 456 457
  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);
458

459 460 461 462 463 464 465 466 467 468
  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);
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510

/* 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));
511 512 513 514 515 516 517 518 519 520
}

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;
521
  gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_width", &tree_view->priv->tab_offset, NULL);
522
  tree_view->priv->n_columns = 0;
523 524 525
  tree_view->priv->header_height = 1;
  tree_view->priv->x_drag = 0;
  tree_view->priv->drag_pos = -1;
526
  tree_view->priv->header_has_focus = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
527 528 529
  tree_view->priv->pressed_button = -1;
  tree_view->priv->press_start_x = -1;
  tree_view->priv->press_start_y = -1;
Jonathan Blandford's avatar
Jonathan Blandford committed
530

531
  gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
532
  _gtk_tree_view_update_size (tree_view);
533 534
}

535

536

537
/* GObject Methods
538 539
 */

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 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 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
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;
    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;
    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;
    }
}

614 615 616 617 618 619
static void
gtk_tree_view_finalize (GObject *object)
{
  GtkTreeView *tree_view = (GtkTreeView *) object;

  g_free (tree_view->priv);
620

621 622 623 624
  if (G_OBJECT_CLASS (parent_class)->finalize)
    (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}

625 626 627 628 629


/* GtkObject Methods
 */

Jonathan Blandford's avatar
Jonathan Blandford committed
630 631 632 633 634 635 636
static void
gtk_tree_view_destroy (GtkObject *object)
{
  GtkTreeView *tree_view = (GtkTreeView *) object;
  GList *list;


637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
  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
664

665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
  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;
    }

  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
Jonathan Blandford's avatar
Jonathan Blandford committed
691 692
}

693 694 695


/* GtkWidget Methods
696 697
 */

698
/* GtkWidget:;map helper */
699
static void
700
gtk_tree_view_map_buttons (GtkTreeView *tree_view)
701
{
702
  GList *list;
703

704
  g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
705

706
  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
707
    {
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
      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);
731 732 733 734
    }
}

static void
735
gtk_tree_view_map (GtkWidget *widget)
736
{
737
  GList *tmp_list;
738 739
  GtkTreeView *tree_view;

740
  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
Jonathan Blandford's avatar
Jonathan Blandford committed
741

742 743 744 745 746 747
  tree_view = GTK_TREE_VIEW (widget);

  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);

  tmp_list = tree_view->priv->children;
  while (tmp_list)
748
    {
749 750 751 752 753 754 755 756
      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);
	}
757
    }
758
  gdk_window_show (tree_view->priv->bin_window);
759

760 761 762 763
  gtk_tree_view_map_buttons (tree_view);

  gdk_window_show (widget->window);
}
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 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

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);
    }
858 859 860 861

  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));

862
  _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878

  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;
    }
879 880 881 882 883 884
}

static void
gtk_tree_view_unrealize (GtkWidget *widget)
{
  GtkTreeView *tree_view;
885
  GList *list;
886 887 888 889 890

  g_return_if_fail (GTK_IS_TREE_VIEW (widget));

  tree_view = GTK_TREE_VIEW (widget);

Havoc Pennington's avatar
Havoc Pennington committed
891 892 893 894 895 896 897 898 899 900 901
  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;
    }
902 903 904 905

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

906 907 908 909 910 911 912 913
  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;

914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
  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;
    }

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

935
  gdk_cursor_destroy (tree_view->priv->cursor_drag);
Jonathan Blandford's avatar
Jonathan Blandford committed
936 937
  gdk_gc_destroy (tree_view->priv->xor_gc);

938
  /* GtkWidget::unrealize destroys children and widget->window */
Jonathan Blandford's avatar
Jonathan Blandford committed
939

940 941 942 943
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}

944
/* GtkWidget::size_request helper */
945
static void
946
gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
947 948 949
{
  GList *list;

950
  tree_view->priv->header_height = 1;
Jonathan Blandford's avatar
Jonathan Blandford committed
951

952
  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
953
    {
954 955 956 957
      for (list = tree_view->priv->columns; list; list = list->next)
        {
          GtkRequisition requisition;
          GtkTreeViewColumn *column;
Jonathan Blandford's avatar
Jonathan Blandford committed
958

959
          column = list->data;
Jonathan Blandford's avatar
Jonathan Blandford committed
960

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

963
          gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
964 965
          tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
        }
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
    }
}

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;

992 993
      if (GTK_WIDGET_VISIBLE (child->widget))
        gtk_widget_size_request (child->widget, &child_requisition);
994
    }
995 996

  gtk_tree_view_size_request_buttons (tree_view);
997 998
}

999
/* GtkWidget::size_allocate helper */
1000 1001 1002 1003 1004 1005 1006 1007
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
1008

1009 1010 1011 1012 1013
  tree_view = GTK_TREE_VIEW (widget);

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

1014
  for (list = tree_view->priv->columns; list != NULL; list = list->next)
1015 1016 1017 1018 1019 1020 1021
    {
      column = list->data;

      if (!column->visible)
	continue;

      allocation.x = width;
1022
      allocation.width = column->displayed_width;
Havoc Pennington's avatar
Havoc Pennington committed
1023
      width += column->width;
1024 1025 1026
      gtk_widget_size_allocate (column->button, &allocation);

      if (column->window)
1027
	gdk_window_move_resize (column->window,
1028 1029
                                allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
				allocation.y,
1030
                                TREE_VIEW_DRAG_WIDTH, allocation.height);
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
    }
}

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
1046

Havoc Pennington's avatar
Havoc Pennington committed
1047
  gtk_tree_view_check_dirty (tree_view);
Jonathan Blandford's avatar
Jonathan Blandford committed
1048

1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
  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);
Havoc Pennington's avatar
Havoc Pennington committed
1073

1074 1075 1076 1077
      gdk_window_move_resize (tree_view->priv->header_window,
			      0, 0,
			      MAX (tree_view->priv->width, allocation->width),
			      tree_view->priv->header_height);
1078 1079 1080 1081 1082 1083 1084

      if (tree_view->priv->width < allocation->width)
	gdk_window_resize (tree_view->priv->bin_window,
			   allocation->width,
			   tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));

      _gtk_tree_view_update_col_width (tree_view);
1085
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
1086

1087 1088
  gtk_tree_view_size_allocate_buttons (widget);

1089 1090 1091 1092
  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
1093

1094 1095 1096 1097 1098 1099 1100 1101
  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
1102

1103 1104
  if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
    gtk_adjustment_set_value (tree_view->priv->vadjustment,
1105
			      MAX (tree_view->priv->height - allocation->height, 0));
Havoc Pennington's avatar
Havoc Pennington committed
1106

1107
  gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
1108

1109 1110
}

1111 1112 1113
static gboolean
gtk_tree_view_button_press (GtkWidget      *widget,
			    GdkEventButton *event)
Havoc Pennington's avatar
Havoc Pennington committed
1114
{
1115
  GtkTreeView *tree_view;
Havoc Pennington's avatar
Havoc Pennington committed
1116
  GList *list;
1117 1118
  GtkTreeViewColumn *column = NULL;
  gint i;
Havoc Pennington's avatar
Havoc Pennington committed
1119
  GdkRectangle background_area;
1120 1121
  GdkRectangle cell_area;
  gint vertical_separator;
Jonathan Blandford's avatar
Jonathan Blandford committed
1122

1123 1124
  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
1125

1126 1127
  tree_view = GTK_TREE_VIEW (widget);
  gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
Havoc Pennington's avatar
Havoc Pennington committed
1128

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
  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
1139

1140 1141 1142
      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
1143

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
      /* 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
1161

1162 1163 1164 1165 1166 1167
      /* 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
1168

1169 1170 1171
      if (node == NULL)
	/* We clicked in dead space */
	return TRUE;
Havoc Pennington's avatar
Havoc Pennington committed
1172

1173 1174 1175 1176 1177 1178 1179
      /* 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
1180

1181 1182 1183 1184 1185 1186
      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
1187

1188
	  column = list->data;
Havoc Pennington's avatar
Havoc Pennington committed
1189

1190 1191
	  if (!column->visible)
	    continue;
Jonathan Blandford's avatar
Jonathan Blandford committed
1192

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
	  background_area.width = column->displayed_width;
	  if (i == tree_view->priv->expander_column &&
              TREE_VIEW_DRAW_EXPANDERS(tree_view))
	    {
	      cell_area = background_area;
	      cell_area.x += depth*tree_view->priv->tab_offset;
	      cell_area.width -= depth*tree_view->priv->tab_offset;
	    }
	  else
	    {
	      cell_area = background_area;
	    }
Jonathan Blandford's avatar
Jonathan Blandford committed
1205

1206
	  cell = column->cell;
Havoc Pennington's avatar
Havoc Pennington committed
1207

1208 1209 1210 1211 1212 1213 1214 1215
	  if ((background_area.x > (gint) event->x) ||
	      (background_area.y > (gint) event->y) ||
	      (background_area.x + background_area.width <= (gint) event->x) ||
	      (background_area.y + background_area.height <= (gint) event->y))
	    {
	      background_area.x += background_area.width;
	      continue;
	    }
Havoc Pennington's avatar
Havoc Pennington committed
1216

1217 1218 1219 1220 1221 1222
	  gtk_tree_model_get_iter (tree_view->priv->model,
				   &iter,
				   path);
	  gtk_tree_view_column_set_cell_data (column,
					      tree_view->priv->model,
					      &iter);
Havoc Pennington's avatar
Havoc Pennington committed
1223

1224
	  path_string = gtk_tree_path_to_string (path);
Havoc Pennington's avatar
Havoc Pennington committed
1225

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
	  g_object_get (G_OBJECT (cell),
			"visible", &visible,
			"can_activate", &can_activate,
			NULL);
	  if (visible &&
	      can_activate &&
	      gtk_cell_renderer_event (cell, (GdkEvent *)event,
				       widget, path_string,
				       &background_area,
				       &cell_area, 0))
	    {
	      g_free (path_string);
	      gtk_tree_path_free (path);
	      return TRUE;
	    }
	  else
	    {
	      g_free (path_string);
	      break;
	    }
	}
Jonathan Blandford's avatar
Jonathan Blandford committed
1247

1248 1249
      if (column == NULL)
	return FALSE;
1250