2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 #include "gtktreeview.h"
22 #include "gtkrbtree.h"
23 #include "gtktreednd.h"
24 #include "gtktreeprivate.h"
25 #include "gtkcellrenderer.h"
26 #include "gtksignal.h"
28 #include "gtkbutton.h"
29 #include "gtkalignment.h"
34 #include "gtkbindings.h"
36 #include <gdk/gdkkeysyms.h>
38 #if defined (GDK_WINDOWING_X11)
40 #elif defined (GDK_WINDOWING_WIN32)
41 #include "win32/gdkwin32.h"
42 #elif defined(GDK_WINDOWING_FB)
43 #include "linux-fb/gdkfb.h"
44 #elif defined (GDK_WINDOWING_NANOX)
45 #include "nanox/gdkprivate-nanox.h"
49 #define SCROLL_EDGE_SIZE 15
52 /* The "background" areas of all rows/cells add up to cover the entire tree.
53 * The background includes all inter-row and inter-cell spacing.
54 * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
55 * i.e. just the cells, no spacing.
57 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (_gtk_rbtree_node_find_offset ((tree), (node)) + TREE_VIEW_HEADER_HEIGHT ((tree_view)))
58 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
60 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
61 #define CELL_HEIGHT(node, separator) (BACKGROUND_HEIGHT (node) - separator);
63 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view))
64 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view))
67 typedef struct _GtkTreeViewChild GtkTreeViewChild;
68 struct _GtkTreeViewChild
76 typedef struct _TreeViewDragInfo TreeViewDragInfo;
77 struct _TreeViewDragInfo
79 GdkModifierType start_button_mask;
80 GtkTargetList *source_target_list;
81 GdkDragAction source_actions;
82 GClosure *row_draggable_closure;
84 GtkTargetList *dest_target_list;
85 GClosure *location_droppable_closure;
101 BEGIN_EXTENDED_SELECTION,
102 END_EXTENDED_SELECTION,
108 EXPAND_COLLAPSE_CURSOR_ROW,
109 SELECT_CURSOR_PARENT,
119 PROP_HEADERS_VISIBLE,
120 PROP_HEADERS_CLICKABLE,
121 PROP_EXPANDER_COLUMN,
126 static void gtk_tree_view_class_init (GtkTreeViewClass *klass);
127 static void gtk_tree_view_init (GtkTreeView *tree_view);
130 static void gtk_tree_view_finalize (GObject *object);
131 static void gtk_tree_view_set_property (GObject *object,
135 static void gtk_tree_view_get_property (GObject *object,
140 /* gtkobject signals */
141 static void gtk_tree_view_destroy (GtkObject *object);
143 /* gtkwidget signals */
144 static void gtk_tree_view_setup_model (GtkTreeView *tree_view);
145 static void gtk_tree_view_realize (GtkWidget *widget);
146 static void gtk_tree_view_unrealize (GtkWidget *widget);
147 static void gtk_tree_view_map (GtkWidget *widget);
148 static void gtk_tree_view_size_request (GtkWidget *widget,
149 GtkRequisition *requisition);
150 static void gtk_tree_view_size_allocate (GtkWidget *widget,
151 GtkAllocation *allocation);
152 static gboolean gtk_tree_view_expose (GtkWidget *widget,
153 GdkEventExpose *event);
154 static gboolean gtk_tree_view_key_press (GtkWidget *widget,
156 static gboolean gtk_tree_view_motion (GtkWidget *widget,
157 GdkEventMotion *event);
158 static gboolean gtk_tree_view_enter_notify (GtkWidget *widget,
159 GdkEventCrossing *event);
160 static gboolean gtk_tree_view_leave_notify (GtkWidget *widget,
161 GdkEventCrossing *event);
162 static gboolean gtk_tree_view_button_press (GtkWidget *widget,
163 GdkEventButton *event);
164 static gboolean gtk_tree_view_button_release (GtkWidget *widget,
165 GdkEventButton *event);
166 static void gtk_tree_view_set_focus_child (GtkContainer *container,
168 static void gtk_tree_view_draw_focus (GtkWidget *widget);
169 static gint gtk_tree_view_focus_in (GtkWidget *widget,
170 GdkEventFocus *event);
171 static gint gtk_tree_view_focus_out (GtkWidget *widget,
172 GdkEventFocus *event);
173 static gint gtk_tree_view_focus (GtkWidget *widget,
174 GtkDirectionType direction);
176 /* container signals */
177 static void gtk_tree_view_remove (GtkContainer *container,
179 static void gtk_tree_view_forall (GtkContainer *container,
180 gboolean include_internals,
181 GtkCallback callback,
182 gpointer callback_data);
184 /* Source side drag signals */
185 static void gtk_tree_view_drag_begin (GtkWidget *widget,
186 GdkDragContext *context);
187 static void gtk_tree_view_drag_end (GtkWidget *widget,
188 GdkDragContext *context);
189 static void gtk_tree_view_drag_data_get (GtkWidget *widget,
190 GdkDragContext *context,
191 GtkSelectionData *selection_data,
194 static void gtk_tree_view_drag_data_delete (GtkWidget *widget,
195 GdkDragContext *context);
197 /* Target side drag signals */
198 static void gtk_tree_view_drag_leave (GtkWidget *widget,
199 GdkDragContext *context,
201 static gboolean gtk_tree_view_drag_motion (GtkWidget *widget,
202 GdkDragContext *context,
206 static gboolean gtk_tree_view_drag_drop (GtkWidget *widget,
207 GdkDragContext *context,
211 static void gtk_tree_view_drag_data_received (GtkWidget *widget,
212 GdkDragContext *context,
215 GtkSelectionData *selection_data,
219 /* tree_model signals */
220 static void gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
222 GtkAdjustment *vadj);
223 static void gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view);
224 static void gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view);
225 static void gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view);
226 static void gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view);
227 static void gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
228 GtkMovementStep step,
230 static void gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view);
231 static void gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view);
232 static void gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
236 static void gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view);
237 static void gtk_tree_view_range_changed (GtkTreeModel *model,
240 GtkTreePath *end_path,
241 GtkTreeIter *end_iter,
243 static void gtk_tree_view_inserted (GtkTreeModel *model,
247 static void gtk_tree_view_has_child_toggled (GtkTreeModel *model,
251 static void gtk_tree_view_deleted (GtkTreeModel *model,
254 static void gtk_tree_view_reordered (GtkTreeModel *model,
262 /* Internal functions */
263 static gboolean gtk_tree_view_is_expander_column (GtkTreeView *tree_view,
264 GtkTreeViewColumn*column);
265 static void gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
268 GtkMovementStep step,
270 static gint gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
272 static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
275 GdkRectangle *clip_rect);
276 static void gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
278 GdkRectangle *clip_rect);
279 static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
284 static void gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
287 static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view,
290 static void gtk_tree_view_ensure_scroll_timeout(GtkTreeView *tree_view,
292 static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
293 GtkTreeView *tree_view);
294 static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
298 static void gtk_tree_view_build_tree (GtkTreeView *tree_view,
303 gboolean calc_bounds);
304 static void gtk_tree_view_calc_size (GtkTreeView *priv,
308 static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
312 static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
316 static void gtk_tree_view_check_dirty (GtkTreeView *tree_view);
317 static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
320 static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
321 GdkEventMotion *event);
322 static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view);
325 static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view);
326 static void gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
328 static void gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
330 static void gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
332 static void gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
334 static gboolean gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
338 static gboolean gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
343 static void gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
345 gboolean clear_and_select);
348 static GtkContainerClass *parent_class = NULL;
349 static guint tree_view_signals[LAST_SIGNAL] = { 0 };
357 gtk_tree_view_get_type (void)
359 static GtkType tree_view_type = 0;
363 static const GTypeInfo tree_view_info =
365 sizeof (GtkTreeViewClass),
366 NULL, /* base_init */
367 NULL, /* base_finalize */
368 (GClassInitFunc) gtk_tree_view_class_init,
369 NULL, /* class_finalize */
370 NULL, /* class_data */
371 sizeof (GtkTreeView),
373 (GInstanceInitFunc) gtk_tree_view_init
376 tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
379 return tree_view_type;
383 gtk_tree_view_class_init (GtkTreeViewClass *class)
385 GObjectClass *o_class;
386 GtkObjectClass *object_class;
387 GtkWidgetClass *widget_class;
388 GtkContainerClass *container_class;
389 GtkBindingSet *binding_set;
391 parent_class = g_type_class_peek_parent (class);
392 binding_set = gtk_binding_set_by_class (class);
394 o_class = (GObjectClass *) class;
395 object_class = (GtkObjectClass *) class;
396 widget_class = (GtkWidgetClass *) class;
397 container_class = (GtkContainerClass *) class;
399 /* GObject signals */
400 o_class->set_property = gtk_tree_view_set_property;
401 o_class->get_property = gtk_tree_view_get_property;
402 o_class->finalize = gtk_tree_view_finalize;
404 /* GtkObject signals */
405 object_class->destroy = gtk_tree_view_destroy;
407 /* GtkWidget signals */
408 widget_class->map = gtk_tree_view_map;
409 widget_class->realize = gtk_tree_view_realize;
410 widget_class->unrealize = gtk_tree_view_unrealize;
411 widget_class->size_request = gtk_tree_view_size_request;
412 widget_class->size_allocate = gtk_tree_view_size_allocate;
413 widget_class->button_press_event = gtk_tree_view_button_press;
414 widget_class->button_release_event = gtk_tree_view_button_release;
415 widget_class->motion_notify_event = gtk_tree_view_motion;
416 widget_class->expose_event = gtk_tree_view_expose;
417 widget_class->key_press_event = gtk_tree_view_key_press;
418 widget_class->enter_notify_event = gtk_tree_view_enter_notify;
419 widget_class->leave_notify_event = gtk_tree_view_leave_notify;
420 widget_class->focus_in_event = gtk_tree_view_focus_in;
421 widget_class->focus_out_event = gtk_tree_view_focus_out;
422 widget_class->drag_begin = gtk_tree_view_drag_begin;
423 widget_class->drag_end = gtk_tree_view_drag_end;
424 widget_class->drag_data_get = gtk_tree_view_drag_data_get;
425 widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
426 widget_class->drag_leave = gtk_tree_view_drag_leave;
427 widget_class->drag_motion = gtk_tree_view_drag_motion;
428 widget_class->drag_drop = gtk_tree_view_drag_drop;
429 widget_class->drag_data_received = gtk_tree_view_drag_data_received;
430 widget_class->focus = gtk_tree_view_focus;
432 /* GtkContainer signals */
433 container_class->remove = gtk_tree_view_remove;
434 container_class->forall = gtk_tree_view_forall;
435 container_class->set_focus_child = gtk_tree_view_set_focus_child;
437 class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
438 class->begin_extended_selection = gtk_tree_view_real_begin_extended_selection;
439 class->end_extended_selection = gtk_tree_view_real_end_extended_selection;
440 class->begin_free_motion = gtk_tree_view_real_begin_free_motion;
441 class->end_free_motion = gtk_tree_view_real_end_free_motion;
442 class->move_cursor = gtk_tree_view_real_move_cursor;
443 class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
444 class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
445 class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
446 class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
450 g_object_class_install_property (o_class,
452 g_param_spec_object ("model",
454 _("The model for the tree view"),
458 g_object_class_install_property (o_class,
460 g_param_spec_object ("hadjustment",
461 _("Horizontal Adjustment"),
462 _("Horizontal Adjustment for the widget"),
466 g_object_class_install_property (o_class,
468 g_param_spec_object ("vadjustment",
469 _("Vertical Adjustment"),
470 _("Vertical Adjustment for the widget"),
474 g_object_class_install_property (o_class,
475 PROP_HEADERS_VISIBLE,
476 g_param_spec_boolean ("headers_visible",
478 _("Show the column header buttons"),
482 g_object_class_install_property (o_class,
483 PROP_HEADERS_CLICKABLE,
484 g_param_spec_boolean ("headers_clickable",
485 _("Headers Clickable"),
486 _("Column headers respond to click events"),
490 g_object_class_install_property (o_class,
491 PROP_EXPANDER_COLUMN,
492 g_param_spec_object ("expander_column",
493 _("Expander Column"),
494 _("Set the column for the expander column"),
495 GTK_TYPE_TREE_VIEW_COLUMN,
498 g_object_class_install_property (o_class,
500 g_param_spec_boolean ("reorderable",
502 _("View is reorderable"),
506 g_object_class_install_property (o_class,
508 g_param_spec_boolean ("rules_hint",
510 _("Set a hint to the theme engine to draw rows in alternating colors"),
514 /* Style properties */
515 /* the width of the column resize windows */
516 #define _TREE_VIEW_EXPANDER_WIDTH 14
517 #define _TREE_VIEW_EXPANDER_HEIGHT 14
518 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
519 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 0
521 gtk_widget_class_install_style_property (widget_class,
522 g_param_spec_int ("expander_width",
524 _("Width of the expander arrow"),
527 _TREE_VIEW_EXPANDER_WIDTH,
530 gtk_widget_class_install_style_property (widget_class,
531 g_param_spec_int ("expander_height",
532 _("Expander Height"),
533 _("Height of the expander arrow"),
536 _TREE_VIEW_EXPANDER_HEIGHT,
539 gtk_widget_class_install_style_property (widget_class,
540 g_param_spec_int ("vertical_separator",
541 _("Vertical Separator Width"),
542 _("Vertical space between cells"),
545 _TREE_VIEW_VERTICAL_SEPARATOR,
548 gtk_widget_class_install_style_property (widget_class,
549 g_param_spec_int ("horizontal_separator",
550 _("Horizontal Separator Width"),
551 _("Horizontal space between cells"),
554 _TREE_VIEW_HORIZONTAL_SEPARATOR,
558 widget_class->set_scroll_adjustments_signal =
559 gtk_signal_new ("set_scroll_adjustments",
561 GTK_CLASS_TYPE (object_class),
562 GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
563 gtk_marshal_VOID__OBJECT_OBJECT,
565 GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
567 tree_view_signals[ROW_ACTIVATED] =
568 gtk_signal_new ("row_activated",
569 GTK_RUN_LAST | GTK_RUN_ACTION,
570 GTK_CLASS_TYPE (object_class),
571 GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
572 gtk_marshal_VOID__BOXED_OBJECT,
575 GTK_TYPE_TREE_VIEW_COLUMN);
577 tree_view_signals[TEST_EXPAND_ROW] =
578 g_signal_new ("test_expand_row",
579 G_TYPE_FROM_CLASS (object_class),
581 G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
582 _gtk_boolean_handled_accumulator, NULL,
583 gtk_marshal_BOOLEAN__BOXED_BOXED,
588 tree_view_signals[TEST_COLLAPSE_ROW] =
589 g_signal_new ("test_collapse_row",
590 G_TYPE_FROM_CLASS (object_class),
592 G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
593 _gtk_boolean_handled_accumulator, NULL,
594 gtk_marshal_BOOLEAN__BOXED_BOXED,
599 tree_view_signals[ROW_EXPANDED] =
600 g_signal_new ("row_expanded",
601 G_TYPE_FROM_CLASS (object_class),
603 G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
605 gtk_marshal_VOID__BOXED_BOXED,
610 tree_view_signals[ROW_COLLAPSED] =
611 g_signal_new ("row_collapsed",
612 G_TYPE_FROM_CLASS (object_class),
614 G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
616 gtk_marshal_VOID__BOXED_BOXED,
621 tree_view_signals[COLUMNS_CHANGED] =
622 g_signal_new ("columns_changed",
623 G_TYPE_FROM_CLASS (object_class),
625 G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
627 gtk_marshal_NONE__NONE,
630 tree_view_signals[BEGIN_EXTENDED_SELECTION] =
631 g_signal_new ("begin_extended_selection",
632 G_TYPE_FROM_CLASS (object_class),
633 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
634 G_STRUCT_OFFSET (GtkTreeViewClass, begin_extended_selection),
636 gtk_marshal_NONE__NONE,
639 tree_view_signals[END_EXTENDED_SELECTION] =
640 g_signal_new ("end_extended_selection",
641 G_TYPE_FROM_CLASS (object_class),
642 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
643 G_STRUCT_OFFSET (GtkTreeViewClass, end_extended_selection),
645 gtk_marshal_NONE__NONE,
648 tree_view_signals[BEGIN_FREE_MOTION] =
649 g_signal_new ("begin_free_motion",
650 G_TYPE_FROM_CLASS (object_class),
651 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
652 G_STRUCT_OFFSET (GtkTreeViewClass, begin_free_motion),
654 gtk_marshal_NONE__NONE,
657 tree_view_signals[END_FREE_MOTION] =
658 g_signal_new ("end_free_motion",
659 G_TYPE_FROM_CLASS (object_class),
660 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
661 G_STRUCT_OFFSET (GtkTreeViewClass, end_free_motion),
663 gtk_marshal_NONE__NONE,
666 tree_view_signals[MOVE_CURSOR] =
667 g_signal_new ("move_cursor",
668 G_TYPE_FROM_CLASS (object_class),
669 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
670 G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
672 gtk_marshal_VOID__ENUM_INT,
673 GTK_TYPE_NONE, 2, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT);
675 tree_view_signals[SELECT_CURSOR_ROW] =
676 g_signal_new ("select_cursor_row",
677 G_TYPE_FROM_CLASS (object_class),
678 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
679 G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
681 gtk_marshal_NONE__NONE,
684 tree_view_signals[TOGGLE_CURSOR_ROW] =
685 g_signal_new ("toggle_cursor_row",
686 G_TYPE_FROM_CLASS (object_class),
687 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
688 G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
690 gtk_marshal_NONE__NONE,
693 tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
694 g_signal_new ("expand_collapse_cursor_row",
695 G_TYPE_FROM_CLASS (object_class),
696 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
697 G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
699 gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
700 GTK_TYPE_NONE, 3, GTK_TYPE_BOOL, GTK_TYPE_BOOL, GTK_TYPE_BOOL);
702 tree_view_signals[SELECT_CURSOR_PARENT] =
703 g_signal_new ("select_cursor_parent",
704 G_TYPE_FROM_CLASS (object_class),
705 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
706 G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
708 gtk_marshal_NONE__NONE,
712 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, 0, "begin_extended_selection", 0);
713 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
714 gtk_binding_entry_add_signal (binding_set, GDK_Control_L, 0, "begin_free_motion", 0);
715 gtk_binding_entry_add_signal (binding_set, GDK_Control_L, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
716 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, 0, "begin_extended_selection", 0);
717 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
718 gtk_binding_entry_add_signal (binding_set, GDK_Control_R, 0, "begin_free_motion", 0);
719 gtk_binding_entry_add_signal (binding_set, GDK_Control_R, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
721 gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
722 GTK_MOVEMENT_DISPLAY_LINES, -1);
724 gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
725 GTK_MOVEMENT_DISPLAY_LINES, 1);
727 gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
728 GTK_MOVEMENT_DISPLAY_LINES, -1);
730 gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
731 GTK_MOVEMENT_DISPLAY_LINES, 1);
733 gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
734 GTK_MOVEMENT_BUFFER_ENDS, -1);
736 gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
737 GTK_MOVEMENT_BUFFER_ENDS, 1);
739 gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
740 GTK_MOVEMENT_PAGES, -1);
742 gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
743 GTK_MOVEMENT_PAGES, 1);
745 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
746 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
749 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
750 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
753 gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "move_cursor", 2,
754 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
757 gtk_binding_entry_add_signal (binding_set, GDK_b, GDK_CONTROL_MASK, "move_cursor", 2,
758 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
761 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
763 gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 0);
765 /* expand and collapse rows */
766 gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
767 GTK_TYPE_BOOL, FALSE,
769 GTK_TYPE_BOOL, FALSE);
770 /* Not doable on US keyboards */
771 gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
772 GTK_TYPE_BOOL, FALSE,
774 GTK_TYPE_BOOL, TRUE);
775 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
776 GTK_TYPE_BOOL, FALSE,
778 GTK_TYPE_BOOL, FALSE);
779 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
780 GTK_TYPE_BOOL, FALSE,
782 GTK_TYPE_BOOL, TRUE);
783 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
784 GTK_TYPE_BOOL, FALSE,
786 GTK_TYPE_BOOL, TRUE);
787 gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
790 GTK_TYPE_BOOL, TRUE);
792 gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
793 GTK_TYPE_BOOL, FALSE,
794 GTK_TYPE_BOOL, FALSE,
795 GTK_TYPE_BOOL, FALSE);
796 gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
797 GTK_TYPE_BOOL, FALSE,
798 GTK_TYPE_BOOL, FALSE,
799 GTK_TYPE_BOOL, TRUE);
800 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
801 GTK_TYPE_BOOL, FALSE,
802 GTK_TYPE_BOOL, FALSE,
803 GTK_TYPE_BOOL, FALSE);
804 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
805 GTK_TYPE_BOOL, FALSE,
806 GTK_TYPE_BOOL, FALSE,
807 GTK_TYPE_BOOL, TRUE);
808 gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
809 GTK_TYPE_BOOL, FALSE,
810 GTK_TYPE_BOOL, FALSE,
811 GTK_TYPE_BOOL, TRUE);
813 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
818 gtk_tree_view_init (GtkTreeView *tree_view)
820 tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
822 GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
824 tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
825 gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_width", &tree_view->priv->tab_offset, NULL);
826 tree_view->priv->n_columns = 0;
827 tree_view->priv->header_height = 1;
828 tree_view->priv->x_drag = 0;
829 tree_view->priv->drag_pos = -1;
830 tree_view->priv->header_has_focus = FALSE;
831 tree_view->priv->pressed_button = -1;
832 tree_view->priv->press_start_x = -1;
833 tree_view->priv->press_start_y = -1;
834 tree_view->priv->reorderable = FALSE;
835 gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
836 tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
837 _gtk_tree_view_update_size (tree_view);
846 gtk_tree_view_set_property (GObject *object,
851 GtkTreeView *tree_view;
853 tree_view = GTK_TREE_VIEW (object);
858 gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (g_value_get_object (value)));
860 case PROP_HADJUSTMENT:
861 gtk_tree_view_set_hadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
863 case PROP_VADJUSTMENT:
864 gtk_tree_view_set_vadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
866 case PROP_HEADERS_VISIBLE:
867 gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
869 case PROP_HEADERS_CLICKABLE:
870 gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
872 case PROP_EXPANDER_COLUMN:
873 gtk_tree_view_set_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (g_value_get_object (value)));
875 case PROP_REORDERABLE:
876 gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
878 case PROP_RULES_HINT:
879 gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
887 gtk_tree_view_get_property (GObject *object,
892 GtkTreeView *tree_view;
894 tree_view = GTK_TREE_VIEW (object);
899 g_value_set_object (value, G_OBJECT (tree_view->priv->model));
901 case PROP_HADJUSTMENT:
902 g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
904 case PROP_VADJUSTMENT:
905 g_value_set_object (value, G_OBJECT (tree_view->priv->vadjustment));
907 case PROP_HEADERS_VISIBLE:
908 g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
910 case PROP_EXPANDER_COLUMN:
911 g_value_set_object (value, G_OBJECT (tree_view->priv->expander_column));
913 case PROP_REORDERABLE:
914 g_value_set_boolean (value, tree_view->priv->reorderable);
916 case PROP_RULES_HINT:
917 g_value_set_boolean (value, tree_view->priv->has_rules);
920 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
926 gtk_tree_view_finalize (GObject *object)
928 GtkTreeView *tree_view = (GtkTreeView *) object;
930 g_free (tree_view->priv);
932 if (G_OBJECT_CLASS (parent_class)->finalize)
933 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
942 gtk_tree_view_destroy (GtkObject *object)
944 GtkTreeView *tree_view = (GtkTreeView *) object;
948 if (tree_view->priv->tree != NULL)
950 gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
951 _gtk_rbtree_free (tree_view->priv->tree);
952 tree_view->priv->tree = NULL;
955 if (tree_view->priv->model != NULL)
957 g_object_unref (G_OBJECT (tree_view->priv->model));
958 tree_view->priv->model = NULL;
961 if (tree_view->priv->columns != NULL)
963 for (list = tree_view->priv->columns; list; list = list->next)
964 g_object_unref (G_OBJECT (list->data));
965 g_list_free (tree_view->priv->columns);
966 tree_view->priv->columns = NULL;
969 if (tree_view->priv->selection != NULL)
971 _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
972 g_object_unref (tree_view->priv->selection);
973 tree_view->priv->selection = NULL;
976 if (tree_view->priv->scroll_to_path != NULL)
978 gtk_tree_path_free (tree_view->priv->scroll_to_path);
979 tree_view->priv->scroll_to_path = NULL;
982 if (tree_view->priv->drag_dest_row != NULL)
984 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
985 tree_view->priv->drag_dest_row = NULL;
989 if (tree_view->priv->column_drop_func_data &&
990 tree_view->priv->column_drop_func_data_destroy)
992 (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
993 tree_view->priv->column_drop_func_data = NULL;
996 if (tree_view->priv->destroy_count_destroy &&
997 tree_view->priv->destroy_count_data)
999 (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
1000 tree_view->priv->destroy_count_data = NULL;
1003 gtk_tree_row_reference_free (tree_view->priv->cursor);
1004 tree_view->priv->cursor = NULL;
1006 gtk_tree_row_reference_free (tree_view->priv->anchor);
1007 tree_view->priv->anchor = NULL;
1009 if (GTK_OBJECT_CLASS (parent_class)->destroy)
1010 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1015 /* GtkWidget Methods
1018 /* GtkWidget::map helper */
1020 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1024 g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1026 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1028 GtkTreeViewColumn *column;
1030 for (list = tree_view->priv->columns; list; list = list->next)
1032 column = list->data;
1033 if (GTK_WIDGET_VISIBLE (column->button) &&
1034 !GTK_WIDGET_MAPPED (column->button))
1035 gtk_widget_map (column->button);
1037 for (list = tree_view->priv->columns; list; list = list->next)
1039 column = list->data;
1040 if (column->visible == FALSE)
1042 if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE)
1044 gdk_window_raise (column->window);
1045 gdk_window_show (column->window);
1048 gdk_window_hide (column->window);
1050 gdk_window_show (tree_view->priv->header_window);
1055 gtk_tree_view_map (GtkWidget *widget)
1058 GtkTreeView *tree_view;
1060 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1062 tree_view = GTK_TREE_VIEW (widget);
1064 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1066 tmp_list = tree_view->priv->children;
1069 GtkTreeViewChild *child = tmp_list->data;
1070 tmp_list = tmp_list->next;
1072 if (GTK_WIDGET_VISIBLE (child->widget))
1074 if (!GTK_WIDGET_MAPPED (child->widget))
1075 gtk_widget_map (child->widget);
1078 gdk_window_show (tree_view->priv->bin_window);
1080 gtk_tree_view_map_buttons (tree_view);
1082 gdk_window_show (widget->window);
1086 gtk_tree_view_realize (GtkWidget *widget)
1089 GtkTreeView *tree_view;
1091 GdkWindowAttr attributes;
1092 gint attributes_mask;
1094 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1096 tree_view = GTK_TREE_VIEW (widget);
1098 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
1099 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1101 /* Make the main, clipping window */
1102 attributes.window_type = GDK_WINDOW_CHILD;
1103 attributes.x = widget->allocation.x;
1104 attributes.y = widget->allocation.y;
1105 attributes.width = widget->allocation.width;
1106 attributes.height = widget->allocation.height;
1107 attributes.wclass = GDK_INPUT_OUTPUT;
1108 attributes.visual = gtk_widget_get_visual (widget);
1109 attributes.colormap = gtk_widget_get_colormap (widget);
1110 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1112 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1114 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1115 &attributes, attributes_mask);
1116 gdk_window_set_user_data (widget->window, widget);
1118 /* Make the window for the tree */
1121 attributes.width = tree_view->priv->width;
1122 attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
1123 attributes.event_mask = GDK_EXPOSURE_MASK |
1125 GDK_POINTER_MOTION_MASK |
1126 GDK_ENTER_NOTIFY_MASK |
1127 GDK_LEAVE_NOTIFY_MASK |
1128 GDK_BUTTON_PRESS_MASK |
1129 GDK_BUTTON_RELEASE_MASK |
1130 gtk_widget_get_events (widget);
1132 tree_view->priv->bin_window = gdk_window_new (widget->window,
1133 &attributes, attributes_mask);
1134 gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1136 /* Make the column header window */
1139 attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1140 attributes.height = tree_view->priv->header_height;
1141 attributes.event_mask = (GDK_EXPOSURE_MASK |
1143 GDK_BUTTON_PRESS_MASK |
1144 GDK_BUTTON_RELEASE_MASK |
1145 GDK_KEY_PRESS_MASK |
1146 GDK_KEY_RELEASE_MASK) |
1147 gtk_widget_get_events (widget);
1149 tree_view->priv->header_window = gdk_window_new (widget->window,
1150 &attributes, attributes_mask);
1151 gdk_window_set_user_data (tree_view->priv->header_window, widget);
1154 values.foreground = (widget->style->white.pixel==0 ?
1155 widget->style->black:widget->style->white);
1156 values.function = GDK_XOR;
1157 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1158 tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
1163 /* Add them all up. */
1164 widget->style = gtk_style_attach (widget->style, widget->window);
1165 gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1166 gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1167 gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1169 tmp_list = tree_view->priv->children;
1172 GtkTreeViewChild *child = tmp_list->data;
1173 tmp_list = tmp_list->next;
1175 gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1178 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1179 _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1181 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1183 if (tree_view->priv->scroll_to_path != NULL ||
1184 tree_view->priv->scroll_to_column != NULL)
1186 gtk_tree_view_scroll_to_cell (tree_view,
1187 tree_view->priv->scroll_to_path,
1188 tree_view->priv->scroll_to_column,
1189 tree_view->priv->scroll_to_row_align,
1190 tree_view->priv->scroll_to_col_align);
1191 if (tree_view->priv->scroll_to_path)
1193 gtk_tree_path_free (tree_view->priv->scroll_to_path);
1194 tree_view->priv->scroll_to_path = NULL;
1196 tree_view->priv->scroll_to_column = NULL;
1201 gtk_tree_view_unrealize (GtkWidget *widget)
1203 GtkTreeView *tree_view;
1206 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1208 tree_view = GTK_TREE_VIEW (widget);
1210 if (tree_view->priv->scroll_timeout != 0)
1212 gtk_timeout_remove (tree_view->priv->scroll_timeout);
1213 tree_view->priv->scroll_timeout = 0;
1216 if (tree_view->priv->open_dest_timeout != 0)
1218 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
1219 tree_view->priv->open_dest_timeout = 0;
1222 for (list = tree_view->priv->columns; list; list = list->next)
1223 _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1225 gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
1226 gdk_window_destroy (tree_view->priv->bin_window);
1227 tree_view->priv->bin_window = NULL;
1229 gdk_window_set_user_data (tree_view->priv->header_window, NULL);
1230 gdk_window_destroy (tree_view->priv->header_window);
1231 tree_view->priv->header_window = NULL;
1233 if (tree_view->priv->drag_window)
1235 gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
1236 gdk_window_destroy (tree_view->priv->drag_window);
1237 tree_view->priv->drag_window = NULL;
1240 if (tree_view->priv->drag_highlight_window)
1242 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
1243 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1244 tree_view->priv->drag_highlight_window = NULL;
1247 if (tree_view->priv->cursor_drag)
1249 gdk_cursor_destroy (tree_view->priv->cursor_drag);
1250 tree_view->priv->cursor_drag = NULL;
1253 if (tree_view->priv->xor_gc)
1255 gdk_gc_destroy (tree_view->priv->xor_gc);
1256 tree_view->priv->xor_gc = NULL;
1259 /* GtkWidget::unrealize destroys children and widget->window */
1260 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1261 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1264 /* GtkWidget::size_request helper */
1266 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
1270 tree_view->priv->header_height = 1;
1272 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
1274 for (list = tree_view->priv->columns; list; list = list->next)
1276 GtkRequisition requisition;
1277 GtkTreeViewColumn *column = list->data;
1279 if (column->button == NULL)
1282 column = list->data;
1284 gtk_widget_size_request (column->button, &requisition);
1286 _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
1287 tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1293 gtk_tree_view_size_request (GtkWidget *widget,
1294 GtkRequisition *requisition)
1296 GtkTreeView *tree_view;
1299 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1301 tree_view = GTK_TREE_VIEW (widget);
1303 requisition->width = tree_view->priv->width;
1304 requisition->height = tree_view->priv->height + tree_view->priv->header_height;
1306 tmp_list = tree_view->priv->children;
1310 GtkTreeViewChild *child = tmp_list->data;
1311 GtkRequisition child_requisition;
1313 tmp_list = tmp_list->next;
1315 if (GTK_WIDGET_VISIBLE (child->widget))
1316 gtk_widget_size_request (child->widget, &child_requisition);
1319 gtk_tree_view_size_request_buttons (tree_view);
1322 /* GtkWidget::size_allocate helper */
1324 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
1326 GtkTreeView *tree_view;
1328 GtkTreeViewColumn *column;
1329 GtkAllocation allocation;
1332 tree_view = GTK_TREE_VIEW (widget);
1335 allocation.height = tree_view->priv->header_height;
1337 for (list = tree_view->priv->columns; list != NULL; list = list->next)
1339 column = list->data;
1341 if (!column->visible)
1344 allocation.x = width;
1345 allocation.width = column->displayed_width;
1346 width += column->width;
1347 gtk_widget_size_allocate (column->button, &allocation);
1350 gdk_window_move_resize (column->window,
1351 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
1353 TREE_VIEW_DRAG_WIDTH, allocation.height);
1358 gtk_tree_view_size_allocate (GtkWidget *widget,
1359 GtkAllocation *allocation)
1362 GtkTreeView *tree_view;
1364 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1366 widget->allocation = *allocation;
1368 tree_view = GTK_TREE_VIEW (widget);
1370 gtk_tree_view_check_dirty (tree_view);
1372 tmp_list = tree_view->priv->children;
1376 GtkAllocation allocation;
1377 GtkRequisition requisition;
1379 GtkTreeViewChild *child = tmp_list->data;
1380 tmp_list = tmp_list->next;
1382 allocation.x = child->x;
1383 allocation.y = child->y;
1384 gtk_widget_get_child_requisition (child->widget, &requisition);
1385 allocation.width = requisition.width;
1386 allocation.height = requisition.height;
1388 gtk_widget_size_allocate (child->widget, &allocation);
1391 if (GTK_WIDGET_REALIZED (widget))
1393 gdk_window_move_resize (widget->window,
1394 allocation->x, allocation->y,
1395 allocation->width, allocation->height);
1396 gdk_window_resize (tree_view->priv->header_window,
1397 MAX (tree_view->priv->width, allocation->width),
1398 tree_view->priv->header_height);
1399 if (tree_view->priv->width < allocation->width)
1400 gdk_window_resize (tree_view->priv->bin_window,
1402 tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
1404 _gtk_tree_view_update_col_width (tree_view);
1407 gtk_tree_view_size_allocate_buttons (widget);
1409 tree_view->priv->hadjustment->page_size = allocation->width;
1410 tree_view->priv->hadjustment->page_increment = allocation->width;
1411 tree_view->priv->hadjustment->step_increment = allocation->width / 10;
1412 tree_view->priv->hadjustment->lower = 0;
1413 tree_view->priv->hadjustment->upper = tree_view->priv->width;
1415 if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
1416 tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
1417 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
1419 tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
1420 tree_view->priv->vadjustment->step_increment = (tree_view->priv->vadjustment->page_size) / 10;
1421 tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
1422 tree_view->priv->vadjustment->lower = 0;
1423 tree_view->priv->vadjustment->upper = tree_view->priv->height;
1425 if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
1426 gtk_adjustment_set_value (tree_view->priv->vadjustment,
1427 MAX (tree_view->priv->height - allocation->height, 0));
1429 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
1434 gtk_tree_view_button_press (GtkWidget *widget,
1435 GdkEventButton *event)
1437 GtkTreeView *tree_view;
1439 GtkTreeViewColumn *column = NULL;
1441 GdkRectangle background_area;
1442 GdkRectangle cell_area;
1443 gint vertical_separator;
1445 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1446 g_return_val_if_fail (event != NULL, FALSE);
1448 tree_view = GTK_TREE_VIEW (widget);
1449 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
1451 if (event->window == tree_view->priv->bin_window)
1460 GtkTreeViewColumn *column = NULL;
1462 if (!GTK_WIDGET_HAS_FOCUS (widget))
1463 gtk_widget_grab_focus (widget);
1464 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1466 /* are we in an arrow? */
1467 if (tree_view->priv->prelight_node &&
1468 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1470 if (event->button == 1)
1472 gtk_grab_add (widget);
1473 tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1474 tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1475 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1476 tree_view->priv->prelight_tree,
1477 tree_view->priv->prelight_node,
1484 /* find the node that was clicked */
1485 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1486 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1487 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1489 &node) + new_y - (gint)event->y;
1492 /* We clicked in dead space */
1495 /* Get the path and the node */
1496 path = _gtk_tree_view_find_path (tree_view, tree, node);
1497 depth = gtk_tree_path_get_depth (path);
1498 background_area.y = y_offset + event->y + vertical_separator;
1499 background_area.height = GTK_RBNODE_GET_HEIGHT (node) - vertical_separator;
1500 background_area.x = 0;
1502 /* Let the column have a chance at selecting it. */
1503 for (list = tree_view->priv->columns; list; list = list->next)
1507 column = list->data;
1509 if (!column->visible)
1512 background_area.width = column->displayed_width;
1513 if (gtk_tree_view_is_expander_column (tree_view, column) &&
1514 TREE_VIEW_DRAW_EXPANDERS(tree_view))
1516 cell_area = background_area;
1517 cell_area.x += depth*tree_view->priv->tab_offset;
1518 cell_area.width -= depth*tree_view->priv->tab_offset;
1522 cell_area = background_area;
1525 if ((background_area.x > (gint) event->x) ||
1526 (background_area.y > (gint) event->y) ||
1527 (background_area.x + background_area.width <= (gint) event->x) ||
1528 (background_area.y + background_area.height <= (gint) event->y))
1530 background_area.x += background_area.width;
1534 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1535 gtk_tree_view_column_cell_set_cell_data (column,
1536 tree_view->priv->model,
1539 path_string = gtk_tree_path_to_string (path);
1541 if (gtk_tree_view_column_cell_event (column,
1547 g_free (path_string);
1548 gtk_tree_path_free (path);
1553 g_free (path_string);
1561 /* The columns didn't want the event. We handle it */
1563 /* Save press to possibly begin a drag
1565 if (tree_view->priv->pressed_button < 0)
1567 tree_view->priv->pressed_button = event->button;
1568 tree_view->priv->press_start_x = event->x;
1569 tree_view->priv->press_start_y = event->y;
1572 gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
1574 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1576 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
1578 if (node->children == NULL)
1579 gtk_tree_view_real_expand_row (tree_view, path,
1582 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1585 gtk_tree_view_row_activated (tree_view, path, column);
1588 gtk_tree_path_free (path);
1592 /* We didn't click in the window. Let's check to see if we clicked on a column resize window.
1594 for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1596 column = list->data;
1597 if (event->window == column->window &&
1598 column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE &&
1603 if (gdk_pointer_grab (column->window, FALSE,
1604 GDK_POINTER_MOTION_HINT_MASK |
1605 GDK_BUTTON1_MOTION_MASK |
1606 GDK_BUTTON_RELEASE_MASK,
1607 NULL, NULL, event->time))
1610 gtk_grab_add (widget);
1611 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1613 /* block attached dnd signal handler */
1614 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1616 gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1618 if (!GTK_WIDGET_HAS_FOCUS (widget))
1619 gtk_widget_grab_focus (widget);
1621 tree_view->priv->drag_pos = i;
1622 tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1628 /* GtkWidget::button_release_event helper */
1630 gtk_tree_view_button_release_drag_column (GtkWidget *widget,
1631 GdkEventButton *event)
1633 GtkTreeView *tree_view;
1634 GtkAllocation allocation;
1636 tree_view = GTK_TREE_VIEW (widget);
1638 allocation = tree_view->priv->drag_column->button->allocation;
1639 allocation.x = tree_view->priv->drag_column_x;
1640 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1641 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
1642 gdk_window_reparent (tree_view->priv->drag_column->button->window,
1643 tree_view->priv->header_window,
1644 tree_view->priv->drag_column_x,
1645 tree_view->priv->drag_column->button->allocation.y);
1646 gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
1648 gtk_widget_size_allocate (tree_view->priv->drag_column->button, &allocation);
1649 gtk_widget_grab_focus (tree_view->priv->drag_column->button);
1651 if (tree_view->priv->cur_reorder &&
1652 tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
1653 gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
1654 tree_view->priv->cur_reorder->left_column);
1655 tree_view->priv->drag_column = NULL;
1656 gdk_window_hide (tree_view->priv->drag_window);
1658 g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
1659 g_list_free (tree_view->priv->column_drag_info);
1660 tree_view->priv->column_drag_info = NULL;
1662 gdk_window_hide (tree_view->priv->drag_highlight_window);
1664 /* Reset our flags */
1665 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
1666 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
1671 /* GtkWidget::button_release_event helper */
1673 gtk_tree_view_button_release_column_resize (GtkWidget *widget,
1674 GdkEventButton *event)
1676 GtkTreeView *tree_view;
1682 tree_view = GTK_TREE_VIEW (widget);
1684 i = tree_view->priv->drag_pos;
1685 tree_view->priv->drag_pos = -1;
1687 /* unblock attached dnd signal handler */
1688 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1690 gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1692 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1693 gtk_widget_get_pointer (widget, &x, NULL);
1694 gtk_grab_remove (widget);
1695 gdk_pointer_ungrab (event->time);
1697 width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1698 _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1704 gtk_tree_view_button_release (GtkWidget *widget,
1705 GdkEventButton *event)
1707 GtkTreeView *tree_view;
1709 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1710 g_return_val_if_fail (event != NULL, FALSE);
1712 tree_view = GTK_TREE_VIEW (widget);
1714 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
1715 return gtk_tree_view_button_release_drag_column (widget, event);
1717 if (tree_view->priv->pressed_button == event->button)
1718 tree_view->priv->pressed_button = -1;
1720 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1721 return gtk_tree_view_button_release_column_resize (widget, event);
1723 if (tree_view->priv->button_pressed_node == NULL)
1726 if (event->button == 1)
1728 gtk_grab_remove (widget);
1729 if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1730 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1732 GtkTreePath *path = NULL;
1734 path = _gtk_tree_view_find_path (tree_view,
1735 tree_view->priv->button_pressed_tree,
1736 tree_view->priv->button_pressed_node);
1737 /* Actually activate the node */
1738 if (tree_view->priv->button_pressed_node->children == NULL)
1739 gtk_tree_view_real_expand_row (tree_view, path,
1740 tree_view->priv->button_pressed_tree,
1741 tree_view->priv->button_pressed_node,
1744 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1745 tree_view->priv->button_pressed_tree,
1746 tree_view->priv->button_pressed_node);
1747 gtk_tree_path_free (path);
1750 tree_view->priv->button_pressed_tree = NULL;
1751 tree_view->priv->button_pressed_node = NULL;
1758 /* GtkWidget::motion_event function set.
1762 coords_are_over_arrow (GtkTreeView *tree_view,
1765 /* these are in tree window coords */
1772 if (!GTK_WIDGET_REALIZED (tree_view))
1775 if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1778 arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
1780 arrow.height = BACKGROUND_HEIGHT (node);
1782 gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
1784 arrow.width = x2 - arrow.x;
1786 return (x >= arrow.x &&
1787 x < (arrow.x + arrow.height) &&
1789 y < (arrow.y + arrow.height));
1793 do_unprelight (GtkTreeView *tree_view,
1794 /* these are in tree window coords */
1798 if (tree_view->priv->prelight_node == NULL)
1801 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1803 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1804 !coords_are_over_arrow (tree_view,
1805 tree_view->priv->prelight_tree,
1806 tree_view->priv->prelight_node,
1809 /* We need to unprelight the old arrow. */
1811 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1813 gtk_tree_view_draw_arrow (tree_view,
1814 tree_view->priv->prelight_tree,
1815 tree_view->priv->prelight_node,
1821 tree_view->priv->prelight_node = NULL;
1822 tree_view->priv->prelight_tree = NULL;
1826 do_prelight (GtkTreeView *tree_view,
1829 /* these are in tree window coords */
1833 if (coords_are_over_arrow (tree_view, tree, node, x, y))
1834 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1836 tree_view->priv->prelight_node = node;
1837 tree_view->priv->prelight_tree = tree;
1839 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1843 ensure_unprelighted (GtkTreeView *tree_view)
1845 do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
1846 g_assert (tree_view->priv->prelight_node == NULL);
1851 /* Our motion arrow is either a box (in the case of the original spot)
1852 * or an arrow. It is expander_width wide.
1875 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
1877 GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
1878 GtkWidget *widget = GTK_WIDGET (tree_view);
1879 GdkBitmap *mask = NULL;
1884 gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
1885 GdkWindowAttr attributes;
1886 guint attributes_mask;
1889 reorder->left_column == tree_view->priv->drag_column ||
1890 reorder->right_column == tree_view->priv->drag_column)
1891 arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
1892 else if (reorder->left_column || reorder->right_column)
1894 GdkRectangle visible_rect;
1895 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
1896 if (reorder->left_column)
1897 x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
1899 x = reorder->right_column->button->allocation.x;
1900 if (x < visible_rect.x)
1901 arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
1902 else if (x > visible_rect.x + visible_rect.width)
1903 arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
1905 arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
1908 /* We want to draw the rectangle over the initial location. */
1909 if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
1914 if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
1917 if (tree_view->priv->drag_highlight_window)
1918 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1920 attributes.window_type = GDK_WINDOW_CHILD;
1921 attributes.wclass = GDK_INPUT_OUTPUT;
1922 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1923 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1924 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
1925 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1926 tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
1927 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
1929 width = tree_view->priv->drag_column->button->allocation.width;
1930 height = tree_view->priv->drag_column->button->allocation.height;
1931 gdk_window_move_resize (tree_view->priv->drag_highlight_window,
1932 tree_view->priv->drag_column_x, 0, width, height);
1934 mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
1935 gc = gdk_gc_new (mask);
1937 gdk_gc_set_foreground (gc, &col);
1938 gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
1940 gdk_gc_set_foreground(gc, &col);
1941 gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
1942 gdk_gc_destroy (gc);
1944 gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
1946 if (mask) gdk_pixmap_unref (mask);
1947 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
1950 else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
1955 gint expander_width;
1957 gtk_widget_style_get (widget,
1958 "expander_height", &width,
1959 "expander_width", &expander_width,
1962 /* Get x, y, width, height of arrow */
1963 if (reorder->left_column)
1965 gdk_window_get_origin (reorder->left_column->button->window, &x, &y);
1966 x += reorder->left_column->button->allocation.width - width/2;
1967 height = reorder->left_column->button->allocation.height;
1971 gdk_window_get_origin (reorder->right_column->button->window, &x, &y);
1973 height = reorder->right_column->button->allocation.height;
1975 y -= expander_width/2; /* The arrow takes up only half the space */
1976 height += expander_width;
1978 /* Create the new window */
1979 if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
1981 if (tree_view->priv->drag_highlight_window)
1982 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1984 attributes.window_type = GDK_WINDOW_TEMP;
1985 attributes.wclass = GDK_INPUT_OUTPUT;
1986 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1987 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1988 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
1989 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1990 attributes.width = width;
1991 attributes.height = height;
1992 tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
1993 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
1995 mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
1996 gc = gdk_gc_new (mask);
1998 gdk_gc_set_foreground (gc, &col);
1999 gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2001 /* Draw the 2 arrows as per above */
2003 gdk_gc_set_foreground (gc, &col);
2004 for (i = 0; i < width; i ++)
2006 if (i == (width/2 - 1))
2008 gdk_draw_line (mask, gc, i, j, i, height - j);
2009 if (i < (width/2 - 1))
2014 gdk_gc_destroy (gc);
2015 gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2017 if (mask) gdk_pixmap_unref (mask);
2020 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
2021 gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2023 else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
2024 arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2029 gint expander_height;
2031 gtk_widget_style_get (widget,
2032 "expander_height", &expander_height,
2033 "expander_width", &width,
2036 /* Get x, y, width, height of arrow */
2037 width = width/2; /* remember, the arrow only takes half the available width */
2038 gdk_window_get_origin (widget->window, &x, &y);
2039 if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2040 x += widget->allocation.width - width;
2042 if (reorder->left_column)
2043 height = reorder->left_column->button->allocation.height;
2045 height = reorder->right_column->button->allocation.height;
2047 y -= expander_height;
2048 height += 2*expander_height;
2050 /* Create the new window */
2051 if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
2052 tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2054 if (tree_view->priv->drag_highlight_window)
2055 gdk_window_destroy (tree_view->priv->drag_highlight_window);
2057 attributes.window_type = GDK_WINDOW_TEMP;
2058 attributes.wclass = GDK_INPUT_OUTPUT;
2059 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2060 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2061 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2062 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2063 attributes.width = width;
2064 attributes.height = height;
2065 tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2066 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2068 mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2069 gc = gdk_gc_new (mask);
2071 gdk_gc_set_foreground (gc, &col);
2072 gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2074 /* Draw the 2 arrows as per above */
2076 gdk_gc_set_foreground (gc, &col);
2077 j = expander_height;
2078 for (i = 0; i < width; i ++)
2081 if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
2085 gdk_draw_line (mask, gc, k, j, k, height - j);
2086 gdk_draw_line (mask, gc, k, 0, k, expander_height - j);
2087 gdk_draw_line (mask, gc, k, height, k, height - expander_height + j);
2090 gdk_gc_destroy (gc);
2091 gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2093 if (mask) gdk_pixmap_unref (mask);
2096 tree_view->priv->drag_column_window_state = arrow_type;
2097 gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2101 g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
2102 gdk_window_hide (tree_view->priv->drag_highlight_window);
2106 gdk_window_show (tree_view->priv->drag_highlight_window);
2107 gdk_window_raise (tree_view->priv->drag_highlight_window);
2111 gtk_tree_view_motion_resize_column (GtkWidget *widget,
2112 GdkEventMotion *event)
2117 if (event->is_hint || event->window != widget->window)
2118 gtk_widget_get_pointer (widget, &x, NULL);
2122 new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget),
2123 GTK_TREE_VIEW (widget)->priv->drag_pos, &x);
2124 if (x != GTK_TREE_VIEW (widget)->priv->x_drag)
2125 _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
2127 /* FIXME: Do we need to scroll */
2128 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2134 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
2136 GtkTreeViewColumnReorder *reorder = NULL;
2140 gdk_window_get_pointer (tree_view->priv->bin_window, &mouse_x, NULL, NULL);
2142 for (list = tree_view->priv->column_drag_info; list; list = list->next)
2144 reorder = (GtkTreeViewColumnReorder *) list->data;
2145 if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
2150 /* if (reorder && reorder == tree_view->priv->cur_reorder)
2153 tree_view->priv->cur_reorder = reorder;
2154 gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
2158 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
2160 GdkRectangle visible_rect;
2165 gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
2167 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2169 /* See if we are near the edge. */
2170 offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
2173 offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
2179 value = CLAMP (tree_view->priv->hadjustment->value + offset,
2180 0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
2181 gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
2188 gtk_tree_view_motion_drag_column (GtkWidget *widget,
2189 GdkEventMotion *event)
2191 GtkTreeView *tree_view = (GtkTreeView *) widget;
2192 GtkTreeViewColumn *column = tree_view->priv->drag_column;
2196 if ((column == NULL) ||
2197 (event->window != tree_view->priv->drag_window))
2200 /* Handle moving the header */
2201 gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
2202 x = CLAMP (x + (gint)event->x - column->drag_x, 0,
2203 MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
2204 gdk_window_move (tree_view->priv->drag_window, x, y);
2206 /* autoscroll, if needed */
2207 gtk_tree_view_horizontal_autoscroll (tree_view);
2208 /* Update the current reorder position and arrow; */
2209 gtk_tree_view_update_current_reorder (tree_view);
2215 gtk_tree_view_motion_bin_window (GtkWidget *widget,
2216 GdkEventMotion *event)
2218 GtkTreeView *tree_view;
2222 GtkRBTree *old_prelight_tree;
2223 GtkRBNode *old_prelight_node;
2225 tree_view = (GtkTreeView *) widget;
2227 if (tree_view->priv->tree == NULL)
2230 gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
2232 old_prelight_tree = tree_view->priv->prelight_tree;
2233 old_prelight_node = tree_view->priv->prelight_node;
2235 do_unprelight (tree_view, event->x, event->y);
2237 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2239 _gtk_rbtree_find_offset (tree_view->priv->tree,
2240 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2247 /* If we are currently pressing down a button, we don't want to prelight anything else. */
2248 if ((tree_view->priv->button_pressed_node != NULL) &&
2249 (tree_view->priv->button_pressed_node != node))
2253 do_prelight (tree_view, tree, node, event->x, new_y);
2255 if (old_prelight_node != tree_view->priv->prelight_node)
2257 if (old_prelight_node)
2258 gtk_tree_view_queue_draw_node (tree_view,
2263 if (tree_view->priv->prelight_node)
2264 gtk_tree_view_queue_draw_node (tree_view,
2265 tree_view->priv->prelight_tree,
2266 tree_view->priv->prelight_node,
2274 gtk_tree_view_motion (GtkWidget *widget,
2275 GdkEventMotion *event)
2277 GtkTreeView *tree_view;
2279 tree_view = (GtkTreeView *) widget;
2281 /* Resizing a column */
2282 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2283 return gtk_tree_view_motion_resize_column (widget, event);
2286 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2287 return gtk_tree_view_motion_drag_column (widget, event);
2289 /* Sanity check it */
2290 if (event->window == tree_view->priv->bin_window)
2291 return gtk_tree_view_motion_bin_window (widget, event);
2296 /* Draws the focus rectangle around the cursor row */
2298 gtk_tree_view_draw_focus (GtkWidget *widget)
2300 GtkTreeView *tree_view;
2301 GtkTreePath *cursor_path;
2302 GtkRBTree *tree = NULL;
2303 GtkRBNode *node = NULL;
2306 gint vertical_separator;
2308 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2310 tree_view = GTK_TREE_VIEW (widget);
2312 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2314 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
2317 if (! gtk_tree_row_reference_valid (tree_view->priv->cursor))
2320 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2322 _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
2326 gtk_tree_path_free (cursor_path);
2330 gdk_drawable_get_size (tree_view->priv->bin_window,
2335 y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2336 gdk_drawable_get_size (tree_view->priv->bin_window,
2339 height = BACKGROUND_HEIGHT (node) - 1;
2340 if (tree_view->priv->focus_column != NULL)
2344 gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
2345 gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column, tree_view->priv->model, &iter);
2347 if (gtk_tree_view_column_cell_can_focus (tree_view->priv->focus_column))
2349 GdkRectangle cell_area;
2353 cell_area.x = tree_view->priv->focus_column->button->allocation.x;
2355 cell_area.width = tree_view->priv->focus_column->displayed_width;
2356 cell_area.height = CELL_HEIGHT (node, vertical_separator);
2358 gtk_tree_view_column_cell_get_size (tree_view->priv->focus_column,
2359 &cell_area, &x_offset, &y_offset, &width, &height);
2363 x = cell_area.x + x_offset - 1;
2364 y = cell_area.y + y_offset - 1 + vertical_separator/2;
2368 gtk_paint_focus (widget->style,
2369 tree_view->priv->bin_window,
2373 x, y, width, height);
2375 gtk_tree_path_free (cursor_path);
2378 /* Warning: Very scary function.
2379 * Modify at your own risk
2382 gtk_tree_view_bin_expose (GtkWidget *widget,
2383 GdkEventExpose *event)
2385 GtkTreeView *tree_view;
2390 GtkRBNode *cursor = NULL;
2391 GtkRBTree *cursor_tree = NULL;
2392 GtkRBNode *drag_highlight = NULL;
2393 GtkRBTree *drag_highlight_tree = NULL;
2396 gint y_offset, x_offset, cell_offset;
2399 GdkRectangle background_area;
2400 GdkRectangle cell_area;
2403 gint bin_window_width;
2404 GtkTreePath *cursor_path;
2405 GtkTreePath *drag_dest_path;
2407 gint vertical_separator;
2409 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2411 tree_view = GTK_TREE_VIEW (widget);
2412 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2414 if (tree_view->priv->tree == NULL)
2417 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
2418 /* we want to account for a potential HEADER offset.
2419 * That is, if the header exists, we want to offset our event by its
2420 * height to find the right node.
2422 new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
2424 /* y_offset is the */
2426 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
2427 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2429 &node) + new_y - event->area.y;
2433 /* find the path for the node */
2434 path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
2437 gtk_tree_model_get_iter (tree_view->priv->model,
2440 depth = gtk_tree_path_get_depth (path);
2441 gtk_tree_path_free (path);
2444 drag_dest_path = NULL;
2446 if (tree_view->priv->cursor)
2447 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2450 _gtk_tree_view_find_node (tree_view, cursor_path,
2451 &cursor_tree, &cursor);
2453 if (tree_view->priv->drag_dest_row)
2454 drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
2457 _gtk_tree_view_find_node (tree_view, drag_dest_path,
2458 &drag_highlight_tree, &drag_highlight);
2460 gdk_drawable_get_size (tree_view->priv->bin_window,
2461 &bin_window_width, NULL);
2463 for (last_column = g_list_last (tree_view->priv->columns);
2465 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2466 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2467 last_column = last_column->prev)
2470 /* Actually process the expose event. To do this, we want to
2471 * start at the first node of the event, and walk the tree in
2472 * order, drawing each successive node.
2479 max_height = BACKGROUND_HEIGHT (node);
2481 x_offset = -event->area.x;
2483 highlight_x = 0; /* should match x coord of first cell */
2485 background_area.y = y_offset + event->area.y;
2486 background_area.height = max_height;
2489 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
2490 flags |= GTK_CELL_RENDERER_PRELIT;
2492 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
2493 flags |= GTK_CELL_RENDERER_SELECTED;
2495 parity = _gtk_rbtree_node_find_parity (tree, node);
2497 for (list = tree_view->priv->columns; list; list = list->next)
2499 GtkTreeViewColumn *column = list->data;
2500 const gchar *detail = NULL;
2502 if (!column->visible)
2505 if (cell_offset > event->area.x + event->area.width ||
2506 cell_offset + column->displayed_width < event->area.x)
2508 cell_offset += column->displayed_width;
2512 if (column->show_sort_indicator)
2513 flags |= GTK_CELL_RENDERER_SORTED;
2515 flags &= ~GTK_CELL_RENDERER_SORTED;
2517 gtk_tree_view_column_cell_set_cell_data (column,
2518 tree_view->priv->model,
2521 background_area.x = cell_offset;
2522 background_area.width = column->displayed_width;
2524 cell_area = background_area;
2525 cell_area.y += vertical_separator / 2;
2526 cell_area.height -= vertical_separator;
2528 /* Select the detail for drawing the cell. relevant
2529 * factors are parity, sortedness, and whether to
2533 /* FIXME when we have style properties, clean this up.
2536 if (tree_view->priv->has_rules)
2538 if (flags & GTK_CELL_RENDERER_SORTED)
2541 detail = "cell_odd_ruled_sorted";
2543 detail = "cell_even_ruled_sorted";
2548 detail = "cell_odd_ruled";
2550 detail = "cell_even_ruled";
2555 if (flags & GTK_CELL_RENDERER_SORTED)
2558 detail = "cell_odd_sorted";
2560 detail = "cell_even_sorted";
2565 detail = "cell_odd";
2567 detail = "cell_even";
2573 /* Draw background */
2574 gtk_paint_flat_box (widget->style,
2576 (flags & GTK_CELL_RENDERER_SELECTED) ?
2577 GTK_STATE_SELECTED : GTK_STATE_NORMAL,
2584 background_area.width,
2585 background_area.height);
2587 if (gtk_tree_view_is_expander_column (tree_view, column) &&
2588 TREE_VIEW_DRAW_EXPANDERS(tree_view))
2590 cell_area.x += depth*tree_view->priv->tab_offset;
2591 cell_area.width -= depth*tree_view->priv->tab_offset;
2593 /* If we have an expander column, the highlight underline
2594 * starts with that column, so that it indicates which
2595 * level of the tree we're dropping at.
2597 highlight_x = cell_area.x;
2599 gtk_tree_view_column_cell_render (column,
2605 if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
2608 gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
2609 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2617 gtk_tree_view_column_cell_render (column,
2624 cell_offset += column->displayed_width;
2627 if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
2628 gtk_tree_view_draw_focus (widget);
2630 if (node == drag_highlight)
2632 /* Draw indicator for the drop
2634 gint highlight_y = -1;
2635 GtkRBTree *tree = NULL;
2636 GtkRBNode *node = NULL;
2639 switch (tree_view->priv->drag_dest_pos)
2641 case GTK_TREE_VIEW_DROP_BEFORE:
2642 highlight_y = background_area.y - vertical_separator/2;
2645 case GTK_TREE_VIEW_DROP_AFTER:
2646 highlight_y = background_area.y + background_area.height + vertical_separator/2;
2649 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2650 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2651 _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
2655 gdk_drawable_get_size (tree_view->priv->bin_window,
2657 gtk_paint_focus (widget->style,
2658 tree_view->priv->bin_window,
2662 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
2663 width - 1, BACKGROUND_HEIGHT (node) - 1);
2668 if (highlight_y >= 0)
2670 gdk_draw_line (event->window,
2671 widget->style->black_gc,
2674 bin_window_width - highlight_x,
2679 y_offset += max_height;
2682 GtkTreeIter parent = iter;
2685 tree = node->children;
2688 g_assert (node != tree->nil);
2690 while (node->left != tree->nil)
2692 has_child = gtk_tree_model_iter_children (tree_view->priv->model,
2698 TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
2702 gboolean done = FALSE;
2705 node = _gtk_rbtree_next (tree, node);
2708 gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
2712 TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
2716 GtkTreeIter parent_iter = iter;
2717 gboolean has_parent;
2719 node = tree->parent_node;
2720 tree = tree->parent_tree;
2722 /* we've run out of tree. It's okay to return though, as
2723 * we'd only break out of the while loop below. */
2725 has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
2731 TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
2737 while (y_offset < event->area.height);
2740 gtk_tree_path_free (cursor_path);
2743 gtk_tree_path_free (drag_dest_path);
2749 gtk_tree_view_expose (GtkWidget *widget,
2750 GdkEventExpose *event)
2752 GtkTreeView *tree_view;
2754 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2756 tree_view = GTK_TREE_VIEW (widget);
2758 if (event->window == tree_view->priv->bin_window)
2759 return gtk_tree_view_bin_expose (widget, event);
2765 gtk_tree_view_key_press (GtkWidget *widget,
2768 GtkTreeView *tree_view = (GtkTreeView *) widget;
2770 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2772 if (event->keyval == GDK_Escape)
2774 tree_view->priv->cur_reorder = NULL;
2775 gtk_tree_view_button_release_drag_column (widget, NULL);
2779 return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
2782 /* FIXME Is this function necessary? Can I get an enter_notify event
2783 * w/o either an expose event or a mouse motion event?
2786 gtk_tree_view_enter_notify (GtkWidget *widget,
2787 GdkEventCrossing *event)
2789 GtkTreeView *tree_view;
2794 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2796 tree_view = GTK_TREE_VIEW (widget);
2798 /* Sanity check it */
2799 if (event->window != tree_view->priv->bin_window)
2802 if (tree_view->priv->tree == NULL)
2805 if ((tree_view->priv->button_pressed_node != NULL) &&
2806 (tree_view->priv->button_pressed_node != node))
2809 /* find the node internally */
2810 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2812 _gtk_rbtree_find_offset (tree_view->priv->tree,
2813 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2820 do_prelight (tree_view, tree, node, event->x, new_y);
2822 if (tree_view->priv->prelight_node)
2823 gtk_tree_view_queue_draw_node (tree_view,
2824 tree_view->priv->prelight_tree,
2825 tree_view->priv->prelight_node,
2832 gtk_tree_view_leave_notify (GtkWidget *widget,
2833 GdkEventCrossing *event)
2835 GtkTreeView *tree_view;
2837 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2839 tree_view = GTK_TREE_VIEW (widget);
2841 if (tree_view->priv->prelight_node)
2842 gtk_tree_view_queue_draw_node (tree_view,
2843 tree_view->priv->prelight_tree,
2844 tree_view->priv->prelight_node,
2847 ensure_unprelighted (tree_view);
2854 gtk_tree_view_focus_in (GtkWidget *widget,
2855 GdkEventFocus *event)
2857 GtkTreeView *tree_view;
2859 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2860 g_return_val_if_fail (event != NULL, FALSE);
2862 tree_view = GTK_TREE_VIEW (widget);
2864 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2866 gtk_widget_queue_draw (widget);
2873 gtk_tree_view_focus_out (GtkWidget *widget,
2874 GdkEventFocus *event)
2876 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2877 g_return_val_if_fail (event != NULL, FALSE);
2879 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2881 gtk_widget_queue_draw (widget);
2882 GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE;
2883 GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE;
2891 set_source_row (GdkDragContext *context,
2892 GtkTreeModel *model,
2893 GtkTreePath *source_row)
2895 g_object_set_data_full (G_OBJECT (context),
2896 "gtk-tree-view-source-row",
2897 source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
2898 (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
2902 get_source_row (GdkDragContext *context)
2904 GtkTreeRowReference *ref =
2905 g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
2908 return gtk_tree_row_reference_get_path (ref);
2915 set_dest_row (GdkDragContext *context,
2916 GtkTreeModel *model,
2917 GtkTreePath *dest_row)
2919 g_object_set_data_full (G_OBJECT (context),
2920 "gtk-tree-view-dest-row",
2921 dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
2922 (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
2926 get_dest_row (GdkDragContext *context)
2928 GtkTreeRowReference *ref =
2929 g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
2932 return gtk_tree_row_reference_get_path (ref);
2937 /* Get/set whether drag_motion requested the drag data and
2938 * drag_data_received should thus not actually insert the data,
2939 * since the data doesn't result from a drop.
2942 set_status_pending (GdkDragContext *context,
2943 GdkDragAction suggested_action)
2945 g_object_set_data (G_OBJECT (context),
2946 "gtk-tree-view-status-pending",
2947 GINT_TO_POINTER (suggested_action));
2950 static GdkDragAction
2951 get_status_pending (GdkDragContext *context)
2953 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
2954 "gtk-tree-view-status-pending"));
2957 static TreeViewDragInfo*
2958 get_info (GtkTreeView *tree_view)
2960 return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
2964 clear_source_info (TreeViewDragInfo *di)
2966 if (di->source_target_list)
2967 gtk_target_list_unref (di->source_target_list);
2969 if (di->row_draggable_closure)
2970 g_closure_unref (di->row_draggable_closure);
2972 di->source_target_list = NULL;
2973 di->row_draggable_closure = NULL;
2977 clear_dest_info (TreeViewDragInfo *di)
2979 if (di->location_droppable_closure)
2980 g_closure_unref (di->location_droppable_closure);
2982 if (di->dest_target_list)
2983 gtk_target_list_unref (di->dest_target_list);
2985 di->location_droppable_closure = NULL;
2986 di->dest_target_list = NULL;
2990 destroy_info (TreeViewDragInfo *di)
2992 clear_source_info (di);
2993 clear_dest_info (di);
2997 static TreeViewDragInfo*
2998 ensure_info (GtkTreeView *tree_view)
3000 TreeViewDragInfo *di;
3002 di = get_info (tree_view);
3006 di = g_new0 (TreeViewDragInfo, 1);
3008 g_object_set_data_full (G_OBJECT (tree_view),
3009 "gtk-tree-view-drag-info",
3011 (GDestroyNotify) destroy_info);
3018 remove_info (GtkTreeView *tree_view)
3020 g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
3025 drag_scan_timeout (gpointer data)
3027 GtkTreeView *tree_view;
3029 GdkModifierType state;
3030 GtkTreePath *path = NULL;
3031 GtkTreeViewColumn *column = NULL;
3032 GdkRectangle visible_rect;
3034 GDK_THREADS_ENTER ();
3036 tree_view = GTK_TREE_VIEW (data);
3038 gdk_window_get_pointer (tree_view->priv->bin_window,
3041 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3043 /* See if we are near the edge. */
3044 if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
3045 (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
3046 (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
3047 (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
3049 gtk_tree_view_get_path_at_pos (tree_view,
3050 tree_view->priv->bin_window,
3059 gtk_tree_view_scroll_to_cell (tree_view,
3064 gtk_tree_path_free (path);
3068 GDK_THREADS_LEAVE ();
3075 remove_scroll_timeout (GtkTreeView *tree_view)
3077 if (tree_view->priv->scroll_timeout != 0)
3079 gtk_timeout_remove (tree_view->priv->scroll_timeout);
3080 tree_view->priv->scroll_timeout = 0;
3084 check_model_dnd (GtkTreeModel *model,
3085 GType required_iface,
3086 const gchar *signal)
3088 if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
3090 g_warning ("You must override the default '%s' handler "
3091 "on GtkTreeView when using models that don't support "
3092 "the %s interface and enabling drag-and-drop. The simplest way to do this "
3093 "is to connect to '%s' and call "
3094 "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
3095 "the default handler from running. Look at the source code "
3096 "for the default handler in gtktreeview.c to get an idea what "
3097 "your handler should do. (gtktreeview.c is in the GTK source "
3098 "code.) If you're using GTK from a language other than C, "
3099 "there may be a more natural way to override default handlers, e.g. via derivation.",
3100 signal, g_type_name (required_iface), signal);
3108 remove_open_timeout (GtkTreeView *tree_view)
3110 if (tree_view->priv->open_dest_timeout != 0)
3112 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
3113 tree_view->priv->open_dest_timeout = 0;
3119 open_row_timeout (gpointer data)
3121 GtkTreeView *tree_view = data;
3122 GtkTreePath *dest_path = NULL;
3123 GtkTreeViewDropPosition pos;
3124 gboolean result = FALSE;
3126 GDK_THREADS_ENTER ();
3128 gtk_tree_view_get_drag_dest_row (tree_view,
3133 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3134 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3136 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
3137 tree_view->priv->open_dest_timeout = 0;
3139 gtk_tree_path_free (dest_path);
3144 gtk_tree_path_free (dest_path);
3149 GDK_THREADS_LEAVE ();
3154 /* Returns TRUE if event should not be propagated to parent widgets */
3156 set_destination_row (GtkTreeView *tree_view,
3157 GdkDragContext *context,
3160 GdkDragAction *suggested_action,
3163 GtkTreePath *path = NULL;
3164 GtkTreeViewDropPosition pos;
3165 GtkTreeViewDropPosition old_pos;
3166 TreeViewDragInfo *di;
3168 GtkTreePath *old_dest_path = NULL;
3170 *suggested_action = 0;
3173 widget = GTK_WIDGET (tree_view);
3175 di = get_info (tree_view);
3179 /* someone unset us as a drag dest, note that if
3180 * we return FALSE drag_leave isn't called
3183 gtk_tree_view_set_drag_dest_row (tree_view,
3185 GTK_TREE_VIEW_DROP_BEFORE);
3187 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3188 remove_open_timeout (GTK_TREE_VIEW (widget));
3190 return FALSE; /* no longer a drop site */
3193 *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
3194 if (*target == GDK_NONE)
3199 if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
3204 /* can't drop here */
3205 remove_open_timeout (tree_view);
3207 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3209 GTK_TREE_VIEW_DROP_BEFORE);
3211 /* don't propagate to parent though */
3217 /* If we left the current row's "open" zone, unset the timeout for
3220 gtk_tree_view_get_drag_dest_row (tree_view,
3224 if (old_dest_path &&
3225 (gtk_tree_path_compare (path, old_dest_path) != 0 ||
3226 !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3227 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
3228 remove_open_timeout (tree_view);
3231 gtk_tree_path_free (old_dest_path);
3233 if (TRUE /* FIXME if the location droppable predicate */)
3235 GtkWidget *source_widget;
3237 *suggested_action = context->suggested_action;
3239 source_widget = gtk_drag_get_source_widget (context);
3241 if (source_widget == widget)
3243 /* Default to MOVE, unless the user has
3244 * pressed ctrl or alt to affect available actions
3246 if ((context->actions & GDK_ACTION_MOVE) != 0)
3247 *suggested_action = GDK_ACTION_MOVE;
3250 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3255 /* can't drop here */
3256 remove_open_timeout (tree_view);
3258 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3260 GTK_TREE_VIEW_DROP_BEFORE);
3266 get_logical_dest_row (GtkTreeView *tree_view)
3269 /* adjust path to point to the row the drop goes in front of */
3270 GtkTreePath *path = NULL;
3271 GtkTreeViewDropPosition pos;
3273 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3278 if (pos == GTK_TREE_VIEW_DROP_BEFORE)
3280 else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
3281 pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3283 /* get first child, drop before it */
3284 gtk_tree_path_append_index (path, 0);
3288 g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
3289 gtk_tree_path_next (path);
3296 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
3297 GdkEventMotion *event)
3299 GdkDragContext *context;
3300 TreeViewDragInfo *di;
3301 GtkTreePath *path = NULL;
3303 gint cell_x, cell_y;
3304 GtkTreeModel *model;
3306 di = get_info (tree_view);
3311 if (tree_view->priv->pressed_button < 0)
3314 if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
3315 tree_view->priv->press_start_x,
3316 tree_view->priv->press_start_y,
3317 event->x, event->y))
3320 model = gtk_tree_view_get_model (tree_view);
3325 button = tree_view->priv->pressed_button;
3326 tree_view->priv->pressed_button = -1;
3328 gtk_tree_view_get_path_at_pos (tree_view,
3329 tree_view->priv->bin_window,
3330 tree_view->priv->press_start_x,
3331 tree_view->priv->press_start_y,
3340 /* FIXME if the path doesn't match the row_draggable predicate,
3341 * return FALSE and free path
3344 /* FIXME Check whether we're a start button, if not return FALSE and
3348 context = gtk_drag_begin (GTK_WIDGET (tree_view),
3349 di->source_target_list,
3354 gtk_drag_set_icon_default (context);
3359 row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
3362 gtk_drag_set_icon_pixmap (context,
3363 gdk_drawable_get_colormap (row_pix),
3366 /* the + 1 is for the black border in the icon */
3367 tree_view->priv->press_start_x + 1,
3370 gdk_pixmap_unref (row_pix);
3373 set_source_row (context, model, path);
3374 gtk_tree_path_free (path);
3381 gtk_tree_view_drag_begin (GtkWidget *widget,
3382 GdkDragContext *context)
3388 gtk_tree_view_drag_end (GtkWidget *widget,
3389 GdkDragContext *context)
3394 /* Default signal implementations for the drag signals */
3396 gtk_tree_view_drag_data_get (GtkWidget *widget,
3397 GdkDragContext *context,
3398 GtkSelectionData *selection_data,
3402 GtkTreeView *tree_view;
3403 GtkTreeModel *model;
3404 TreeViewDragInfo *di;
3405 GtkTreePath *source_row;
3407 tree_view = GTK_TREE_VIEW (widget);
3409 model = gtk_tree_view_get_model (tree_view);
3414 di = get_info (GTK_TREE_VIEW (widget));
3419 source_row = get_source_row (context);
3421 if (source_row == NULL)
3424 /* We can implement the GTK_TREE_MODEL_ROW target generically for
3425 * any model; for DragSource models there are some other targets
3429 if (GTK_IS_TREE_DRAG_SOURCE (model) &&
3430 gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
3435 /* If drag_data_get does nothing, try providing row data. */
3436 if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3438 gtk_selection_data_set_tree_row (selection_data,
3444 gtk_tree_path_free (source_row);
3449 gtk_tree_view_drag_data_delete (GtkWidget *widget,
3450 GdkDragContext *context)
3452 TreeViewDragInfo *di;
3453 GtkTreeModel *model;
3454 GtkTreeView *tree_view;
3455 GtkTreePath *source_row;
3457 tree_view = GTK_TREE_VIEW (widget);
3458 model = gtk_tree_view_get_model (tree_view);
3460 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
3463 di = get_info (tree_view);
3468 source_row = get_source_row (context);
3470 if (source_row == NULL)
3473 gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
3476 gtk_tree_path_free (source_row);
3478 set_source_row (context, NULL, NULL);
3482 gtk_tree_view_drag_leave (GtkWidget *widget,
3483 GdkDragContext *context,
3486 TreeViewDragInfo *di;
3488 di = get_info (GTK_TREE_VIEW (widget));
3490 /* unset any highlight row */
3491 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3493 GTK_TREE_VIEW_DROP_BEFORE);
3495 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3496 remove_open_timeout (GTK_TREE_VIEW (widget));
3501 gtk_tree_view_drag_motion (GtkWidget *widget,
3502 GdkDragContext *context,
3507 GtkTreePath *path = NULL;
3508 GtkTreeViewDropPosition pos;
3509 GtkTreeView *tree_view;
3510 GdkDragAction suggested_action = 0;
3513 tree_view = GTK_TREE_VIEW (widget);
3515 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3518 // gtk_tree_view_ensure_scroll_timeout (tree_view);
3520 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3524 /* Can't drop here. */
3525 gdk_drag_status (context, 0, time);
3529 if (tree_view->priv->open_dest_timeout == 0 &&
3530 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3531 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3533 tree_view->priv->open_dest_timeout =
3534 gtk_timeout_add (500, open_row_timeout, tree_view);
3537 if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3539 /* Request data so we can use the source row when
3540 * determining whether to accept the drop
3542 set_status_pending (context, suggested_action);
3543 gtk_drag_get_data (widget, context, target, time);
3547 set_status_pending (context, 0);
3548 gdk_drag_status (context, suggested_action, time);
3553 gtk_tree_path_free (path);
3560 gtk_tree_view_drag_drop (GtkWidget *widget,
3561 GdkDragContext *context,
3566 GtkTreeView *tree_view;
3568 GdkDragAction suggested_action = 0;
3569 GdkAtom target = GDK_NONE;
3570 TreeViewDragInfo *di;
3571 GtkTreeModel *model;
3573 tree_view = GTK_TREE_VIEW (widget);
3575 model = gtk_tree_view_get_model (tree_view);
3577 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3578 remove_open_timeout (GTK_TREE_VIEW (widget));
3580 di = get_info (tree_view);
3585 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
3588 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3591 path = get_logical_dest_row (tree_view);
3593 if (target != GDK_NONE && path != NULL)
3595 /* in case a motion had requested drag data, change things so we
3596 * treat drag data receives as a drop.
3598 set_status_pending (context, 0);
3600 set_dest_row (context, model, path);
3604 gtk_tree_path_free (path);
3606 /* Unset this thing */
3607 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3609 GTK_TREE_VIEW_DROP_BEFORE);
3611 if (target != GDK_NONE)
3613 gtk_drag_get_data (widget, context, target, time);
3621 gtk_tree_view_drag_data_received (GtkWidget *widget,
3622 GdkDragContext *context,
3625 GtkSelectionData *selection_data,
3630 TreeViewDragInfo *di;
3631 gboolean accepted = FALSE;
3632 GtkTreeModel *model;
3633 GtkTreeView *tree_view;
3634 GtkTreePath *dest_row;
3635 GdkDragAction suggested_action;
3637 tree_view = GTK_TREE_VIEW (widget);
3639 model = gtk_tree_view_get_model (tree_view);
3641 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
3644 di = get_info (tree_view);
3649 suggested_action = get_status_pending (context);
3651 if (suggested_action)
3653 /* We are getting this data due to a request in drag_motion,
3654 * rather than due to a request in drag_drop, so we are just
3655 * supposed to call drag_status, not actually paste in the
3658 path = get_logical_dest_row (tree_view);
3661 suggested_action = 0;
3663 if (suggested_action)
3665 GtkTreeModel *src_model = NULL;
3666 GtkTreePath *src_path = NULL;
3668 if (!gtk_selection_data_get_tree_row (selection_data,
3671 suggested_action = 0;
3673 if (suggested_action)
3675 if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
3679 suggested_action = 0;
3681 gtk_tree_path_free (src_path);
3685 gdk_drag_status (context, suggested_action, time);
3688 gtk_tree_path_free (path);
3690 /* If you can't drop, remove user drop indicator until the next motion */
3691 if (suggested_action == 0)
3692 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3694 GTK_TREE_VIEW_DROP_BEFORE);
3699 dest_row = get_dest_row (context);
3701 if (dest_row == NULL)
3704 if (selection_data->length >= 0)
3706 if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
3712 gtk_drag_finish (context,
3714 (context->action == GDK_ACTION_MOVE),
3717 gtk_tree_path_free (dest_row);
3720 set_dest_row (context, NULL, NULL);
3725 /* GtkContainer Methods
3730 gtk_tree_view_remove (GtkContainer *container,
3733 GtkTreeView *tree_view;
3734 GtkTreeViewChild *child = NULL;
3737 g_return_if_fail (GTK_IS_TREE_VIEW (container));
3739 tree_view = GTK_TREE_VIEW (container);
3741 tmp_list = tree_view->priv->children;
3744 child = tmp_list->data;
3745 if (child->widget == widget)
3747 gtk_widget_unparent (widget);
3749 tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
3750 g_list_free_1 (tmp_list);
3755 tmp_list = tmp_list->next;
3758 tmp_list = tree_view->priv->columns;
3762 GtkTreeViewColumn *column;
3763 column = tmp_list->data;
3764 if (column->button == widget)
3766 gtk_widget_unparent (widget);
3769 tmp_list = tmp_list->next;
3775 gtk_tree_view_forall (GtkContainer *container,
3776 gboolean include_internals,
3777 GtkCallback callback,
3778 gpointer callback_data)
3780 GtkTreeView *tree_view;
3781 GtkTreeViewChild *child = NULL;
3782 GtkTreeViewColumn *column;
3785 g_return_if_fail (GTK_IS_TREE_VIEW (container));
3786 g_return_if_fail (callback != NULL);
3788 tree_view = GTK_TREE_VIEW (container);
3790 tmp_list = tree_view->priv->children;
3793 child = tmp_list->data;
3794 tmp_list = tmp_list->next;
3796 (* callback) (child->widget, callback_data);
3798 if (include_internals == FALSE)
3801 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3803 column = tmp_list->data;
3806 (* callback) (column->button, callback_data);
3810 /* Returns TRUE if the focus is within the headers, after the focus operation is
3814 gtk_tree_view_header_focus (GtkTreeView *tree_view,
3815 GtkDirectionType dir)
3817 GtkWidget *focus_child;
3818 GtkContainer *container;
3820 GList *last_column, *first_column;
3823 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
3826 focus_child = GTK_CONTAINER (tree_view)->focus_child;
3827 container = GTK_CONTAINER (tree_view);
3829 last_column = g_list_last (tree_view->priv->columns);
3832 if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
3833 GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
3835 last_column = last_column->prev;
3838 /* No headers are visible, or are focusable. We can't focus in or out.
3840 if (last_column == NULL)
3843 first_column = tree_view->priv->columns;
3844 while (first_column)
3846 if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
3847 GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
3849 first_column = first_column->next;
3854 case GTK_DIR_TAB_BACKWARD:
3855 case GTK_DIR_TAB_FORWARD:
3858 if (focus_child == NULL)
3860 if (tree_view->priv->focus_column != NULL)
3861 focus_child = tree_view->priv->focus_column->button;
3863 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3864 gtk_widget_grab_focus (focus_child);
3871 if (focus_child == NULL)
3873 if (tree_view->priv->focus_column != NULL)
3874 focus_child = tree_view->priv->focus_column->button;
3875 else if (dir == GTK_DIR_LEFT)
3876 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3878 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3879 gtk_widget_grab_focus (focus_child);
3883 if (gtk_widget_child_focus (focus_child, dir))
3885 /* The focus moves inside the button. */
3886 /* This is probably a great example of bad UI */
3890 /* We need to move the focus among the row of buttons. */
3891 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3892 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3895 if (tmp_list == first_column && dir == GTK_DIR_LEFT)
3897 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3898 gtk_widget_grab_focus (focus_child);
3901 else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
3903 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3904 gtk_widget_grab_focus (focus_child);
3910 GtkTreeViewColumn *column;
3912 if (dir == GTK_DIR_RIGHT)
3913 tmp_list = tmp_list->next;
3915 tmp_list = tmp_list->prev;
3917 if (tmp_list == NULL)
3919 g_warning ("Internal button not found");
3922 column = tmp_list->data;
3923 if (column->button &&
3925 GTK_WIDGET_CAN_FOCUS (column->button))
3927 focus_child = column->button;
3928 gtk_widget_grab_focus (column->button);
3934 g_assert_not_reached ();
3938 /* if focus child is non-null, we assume it's been set to the current focus child
3942 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3943 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3946 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3948 /* If the following isn't true, then the view is smaller then the scrollpane.
3950 if ((focus_child->allocation.x + focus_child->allocation.width) <=
3951 (tree_view->priv->hadjustment->upper))
3953 /* Scroll to the button, if needed */
3954 if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
3955 (focus_child->allocation.x + focus_child->allocation.width))
3956 gtk_adjustment_set_value (tree_view->priv->hadjustment,
3957 focus_child->allocation.x + focus_child->allocation.width -
3958 tree_view->priv->hadjustment->page_size);
3959 else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
3960 gtk_adjustment_set_value (tree_view->priv->hadjustment,
3961 focus_child->allocation.x);
3965 return (focus_child != NULL);
3968 /* We make the assumption that if container->focus_child != NULL, the focus must
3969 * be in the header. For now, this is accurate. It may not be in the future.
3972 /* The sordid relationship between focus_column and scroll_column:
3974 * The focus_column represents the column that currently has keyboard focus, and
3975 * is used when navigating columns by keyboard. scroll_column is used for
3976 * handling scrolling by keyboard, such that in cases.
3979 gtk_tree_view_focus (GtkWidget *widget,
3980 GtkDirectionType direction)
3982 GtkTreeView *tree_view;
3983 GtkWidget *focus_child;
3984 GtkContainer *container;
3986 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3987 g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
3989 container = GTK_CONTAINER (widget);
3990 tree_view = GTK_TREE_VIEW (widget);
3992 if (!GTK_WIDGET_IS_SENSITIVE (container))
3995 focus_child = container->focus_child;
3997 /* Case 1. Headers currently have focus. */
4004 gtk_tree_view_header_focus (tree_view, direction);
4006 case GTK_DIR_TAB_BACKWARD:
4009 case GTK_DIR_TAB_FORWARD:
4011 if (tree_view->priv->tree == NULL)
4013 gtk_tree_view_focus_to_cursor (tree_view);
4018 /* Case 2. We don't have focus at all. */
4019 if (!GTK_WIDGET_HAS_FOCUS (container))
4021 if (tree_view->priv->tree == NULL &&
4022 (direction == GTK_DIR_TAB_BACKWARD ||
4023 direction == GTK_DIR_UP))
4024 return gtk_tree_view_header_focus (tree_view, direction);
4025 if (((direction == GTK_DIR_TAB_FORWARD) ||
4026 (direction == GTK_DIR_RIGHT) ||
4027 (direction == GTK_DIR_DOWN) ||
4028 (direction == GTK_DIR_LEFT)) &&
4029 gtk_tree_view_header_focus (tree_view, direction))
4032 if (tree_view->priv->tree == NULL)
4034 gtk_tree_view_focus_to_cursor (tree_view);
4038 /* Case 3. We have focus already. */
4039 if (tree_view->priv->tree == NULL)
4040 return gtk_tree_view_header_focus (tree_view, direction);
4042 if (direction == GTK_DIR_TAB_BACKWARD)
4043 return (gtk_tree_view_header_focus (tree_view, direction));
4044 else if (direction == GTK_DIR_TAB_FORWARD)
4047 /* Other directions caught by the keybindings */
4048 gtk_tree_view_focus_to_cursor (tree_view);
4054 gtk_tree_view_set_focus_child (GtkContainer *container,
4057 GtkTreeView *tree_view = GTK_TREE_VIEW (container);
4060 for (list = tree_view->priv->columns; list; list = list->next)
4062 if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
4064 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
4069 (* parent_class->set_focus_child) (container, child);
4073 gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
4074 GtkAdjustment *hadj,
4075 GtkAdjustment *vadj)
4077 gboolean need_adjust = FALSE;
4079 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4082 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4084 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4086 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4088 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4090 if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4092 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4093 gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4096 if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4098 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4099 gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4102 if (tree_view->priv->hadjustment != hadj)
4104 tree_view->priv->hadjustment = hadj;
4105 gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4106 gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4108 gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4109 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4114 if (tree_view->priv->vadjustment != vadj)
4116 tree_view->priv->vadjustment = vadj;
4117 gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4118 gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4120 gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4121 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4127 gtk_tree_view_adjustment_changed (NULL, tree_view);
4131 gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view)
4133 tree_view->priv->in_extended_selection = TRUE;
4137 gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view)
4139 tree_view->priv->in_extended_selection = FALSE;
4143 gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view)
4145 tree_view->priv->in_free_motion = TRUE;
4149 gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view)
4151 tree_view->priv->in_free_motion = FALSE;
4155 gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
4156 GtkMovementStep step,
4159 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4160 g_return_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
4161 step == GTK_MOVEMENT_VISUAL_POSITIONS ||
4162 step == GTK_MOVEMENT_DISPLAY_LINES ||
4163 step == GTK_MOVEMENT_PAGES ||
4164 step == GTK_MOVEMENT_BUFFER_ENDS);
4166 if (tree_view->priv->tree == NULL)
4169 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
4170 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
4174 /* currently we make no distinction. When we go bi-di, we need to */
4175 case GTK_MOVEMENT_LOGICAL_POSITIONS:
4176 case GTK_MOVEMENT_VISUAL_POSITIONS:
4177 gtk_tree_view_move_cursor_left_right (tree_view, count);
4179 case GTK_MOVEMENT_DISPLAY_LINES:
4180 gtk_tree_view_move_cursor_up_down (tree_view, count);
4182 case GTK_MOVEMENT_PAGES:
4183 gtk_tree_view_move_cursor_page_up_down (tree_view, count);
4185 case GTK_MOVEMENT_BUFFER_ENDS:
4186 gtk_tree_view_move_cursor_start_end (tree_view, count);
4189 g_assert_not_reached ();
4193 /* TreeModel Callbacks
4197 gtk_tree_view_range_changed (GtkTreeModel *model,
4200 GtkTreePath *end_path,
4201 GtkTreeIter *end_iter,
4204 GtkTreeView *tree_view = (GtkTreeView *)data;
4208 gboolean dirty_marked;
4209 gboolean free_path = FALSE;
4210 gint vertical_separator;
4213 g_return_if_fail (path != NULL || iter != NULL);
4215 gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
4219 path = gtk_tree_model_get_path (model, iter);
4222 else if (iter == NULL)
4223 gtk_tree_model_get_iter (model, iter, path);
4225 if (_gtk_tree_view_find_node (tree_view,
4229 /* We aren't actually showing the node */
4235 dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
4237 gtk_tree_path_get_depth (path),
4240 if (GTK_RBNODE_GET_HEIGHT (node) != height + vertical_separator)
4242 _gtk_rbtree_node_set_height (tree, node, height + vertical_separator);
4243 gtk_widget_queue_resize (GTK_WIDGET (data));
4247 gtk_widget_queue_resize (GTK_WIDGET (data));
4249 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
4253 gtk_tree_path_free (path);
4257 gtk_tree_view_inserted (GtkTreeModel *model,
4262 GtkTreeView *tree_view = (GtkTreeView *) data;
4264 GtkRBTree *tmptree, *tree;
4265 GtkRBNode *tmpnode = NULL;
4269 gboolean free_path = FALSE;
4271 if (tree_view->priv->tree == NULL)
4272 tree_view->priv->tree = _gtk_rbtree_new ();
4274 tmptree = tree = tree_view->priv->tree;
4275 g_return_if_fail (path != NULL || iter != NULL);
4279 path = gtk_tree_model_get_path (model, iter);
4282 else if (iter == NULL)
4283 gtk_tree_model_get_iter (model, iter, path);
4285 /* Update all row-references */
4286 gtk_tree_row_reference_inserted (G_OBJECT (data), path);
4288 depth = gtk_tree_path_get_depth (path);
4289 indices = gtk_tree_path_get_indices (path);
4291 /* First, find the parent tree */
4292 while (i < depth - 1)
4294 if (tmptree == NULL)
4296 /* We aren't showing the node */
4300 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
4301 if (tmpnode == NULL)
4303 g_warning ("A node was inserted with a parent that's not in the tree.\n" \
4304 "This possibly means that a GtkTreeModel inserted a child node\n" \
4305 "before the parent was inserted.");
4308 else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
4310 /* FIXME enforce correct behavior on model, probably */
4311 /* In theory, the model should have emitted has_child_toggled here. We
4312 * try to catch it anyway, just to be safe, in case the model hasn't.
4314 GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
4317 gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
4318 gtk_tree_path_free (tmppath);
4322 tmptree = tmpnode->children;
4331 gtk_tree_model_ref_node (tree_view->priv->model, iter);
4332 max_height = gtk_tree_view_insert_iter_height (tree_view,
4336 if (indices[depth - 1] == 0)
4338 tmpnode = _gtk_rbtree_find_count (tree, 1);
4339 _gtk_rbtree_insert_before (tree, tmpnode, max_height);
4343 tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
4344 _gtk_rbtree_insert_after (tree, tmpnode, max_height);
4347 _gtk_tree_view_update_size (tree_view);
4351 gtk_tree_path_free (path);
4355 gtk_tree_view_has_child_toggled (GtkTreeModel *model,
4360 GtkTreeView *tree_view = (GtkTreeView *)data;
4361 GtkTreeIter real_iter;
4365 gboolean free_path = FALSE;
4367 g_return_if_fail (path != NULL || iter != NULL);
4374 path = gtk_tree_model_get_path (model, iter);
4377 else if (iter == NULL)
4378 gtk_tree_model_get_iter (model, &real_iter, path);
4380 if (_gtk_tree_view_find_node (tree_view,
4384 /* We aren't actually showing the node */
4390 has_child = gtk_tree_model_iter_has_child (model, &real_iter);
4393 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
4397 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
4399 GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
4401 if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
4403 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4404 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
4408 for (list = tree_view->priv->columns; list; list = list->next)
4409 if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
4411 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
4415 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4419 /* FIXME: Just redraw the node */
4420 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4425 gtk_tree_path_free (path);
4429 count_children_helper (GtkRBTree *tree,
4434 _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
4435 (*((gint *)data))++;
4439 gtk_tree_view_deleted (GtkTreeModel *model,
4443 GtkTreeView *tree_view = (GtkTreeView *)data;
4448 g_return_if_fail (path != NULL);
4450 if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
4456 gtk_tree_row_reference_deleted (G_OBJECT (data), path);
4458 /* Change the selection */
4459 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4460 g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
4462 for (list = tree_view->priv->columns; list; list = list->next)
4463 if (((GtkTreeViewColumn *)list->data)->visible &&
4464 ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4465 ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
4467 /* Ensure we don't have a dangling pointer to a dead node */
4468 ensure_unprelighted (tree_view);
4470 if (tree_view->priv->destroy_count_func)
4472 gint child_count = 0;
4474 _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
4475 (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
4478 if (tree->root->count == 1)
4480 if (tree_view->priv->tree == tree)
4481 tree_view->priv->tree = NULL;
4483 _gtk_rbtree_remove (tree);
4487 _gtk_rbtree_remove_node (tree, node);
4490 _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
4495 gtk_tree_view_reordered (GtkTreeModel *model,
4496 GtkTreePath *parent,
4501 GtkTreeView *tree_view = GTK_TREE_VIEW (data);
4506 len = gtk_tree_model_iter_n_children (model, iter);
4511 gtk_tree_row_reference_reordered (G_OBJECT (data),
4516 if (_gtk_tree_view_find_node (tree_view,
4522 /* We need to special case the parent path */
4524 tree = tree_view->priv->tree;
4526 tree = node->children;
4531 /* FIXME: we need to unprelight our tree, if it's prelit. */
4532 _gtk_rbtree_reorder (tree, new_order, len);
4534 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4538 /* Internal tree functions
4543 gtk_tree_view_get_background_xrange (GtkTreeView *tree_view,
4545 GtkTreeViewColumn *column,
4549 GtkTreeViewColumn *tmp_column = NULL;
4560 for (list = tree_view->priv->columns; list; list = list->next)
4562 tmp_column = list->data;
4564 if (tmp_column == column)
4567 if (tmp_column->visible)
4568 total_width += tmp_column->width;
4571 if (tmp_column != column)
4573 g_warning (G_STRLOC": passed-in column isn't in the tree");
4582 if (column->visible)
4583 *x2 = total_width + column->width;
4585 *x2 = total_width; /* width of 0 */
4590 gtk_tree_view_get_cell_xrange (GtkTreeView *tree_view,
4592 GtkTreeViewColumn *column,
4596 GtkTreeViewColumn *tmp_column = NULL;
4607 for (list = tree_view->priv->columns; list; list = list->next)
4609 tmp_column = list->data;
4611 if (tmp_column == column)
4614 if (tmp_column->visible)
4615 total_width += tmp_column->width;
4618 if (tmp_column != column)
4620 g_warning (G_STRLOC": passed-in column isn't in the tree");
4624 /* Remember we're getting the cell range, i.e. the cell_area passed
4625 * to the cell renderer.
4628 if (gtk_tree_view_is_expander_column (tree_view, column))
4629 total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
4636 if (column->visible)
4637 *x2 = total_width + column->displayed_width;
4639 *x2 = total_width; /* width of 0 */
4644 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
4650 GtkTreeViewColumn *tmp_column = NULL;
4654 for (list = tree_view->priv->columns; list; list = list->next)
4656 tmp_column = list->data;
4658 if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
4660 x_offset = total_width;
4664 if (tmp_column->visible)
4665 total_width += tmp_column->width;
4671 if (tmp_column && tmp_column->visible)
4673 /* +1 because x2 isn't included in the range. */
4675 *x2 = x_offset + tree_view->priv->tab_offset + 1;
4679 /* return an empty range, the expander column is hidden */
4686 gtk_tree_view_setup_model (GtkTreeView *tree_view)
4691 tree_view->priv->tree = NULL;
4693 g_signal_connect (tree_view->priv->model,
4695 (GCallback) gtk_tree_view_range_changed,
4697 g_signal_connect (tree_view->priv->model,
4699 (GCallback) gtk_tree_view_inserted,
4701 g_signal_connect (tree_view->priv->model,
4702 "has_child_toggled",
4703 (GCallback) gtk_tree_view_has_child_toggled,
4705 g_signal_connect (tree_view->priv->model,
4707 (GCallback) gtk_tree_view_deleted,
4709 g_signal_connect (tree_view->priv->model,
4711 (GCallback) gtk_tree_view_reordered,
4714 if (tree_view->priv->columns == NULL)
4717 path = gtk_tree_path_new_root ();
4719 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
4721 tree_view->priv->tree = _gtk_rbtree_new ();
4722 gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
4725 gtk_tree_path_free (path);
4727 /* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
4729 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
4733 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
4738 GtkTreeViewColumn *column;
4740 gint max_height = 0;
4741 gint vertical_separator;
4743 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4744 /* do stuff with node */
4745 for (list = tree_view->priv->columns; list; list = list->next)
4747 gint height = 0, width = 0;
4748 column = list->data;
4750 if (!column->visible)
4753 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4756 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4758 gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4759 max_height = MAX (max_height, vertical_separator + height);
4761 if (gtk_tree_view_is_expander_column (tree_view, column) &&
4762 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4763 _gtk_tree_view_column_set_width (column,
4764 MAX (column->width, depth * tree_view->priv->tab_offset + width));
4766 _gtk_tree_view_column_set_width (column,
4767 MAX (column->width, width));
4773 gtk_tree_view_build_tree (GtkTreeView *tree_view,
4778 gboolean calc_bounds)
4780 GtkRBNode *temp = NULL;
4787 max_height = gtk_tree_view_insert_iter_height (tree_view,
4792 gtk_tree_model_ref_node (tree_view->priv->model, iter);
4793 temp = _gtk_rbtree_insert_after (tree, temp, max_height);
4798 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4800 temp->children = _gtk_rbtree_new ();
4801 temp->children->parent_tree = tree;
4802 temp->children->parent_node = temp;
4803 gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
4806 if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
4808 if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
4809 temp->flags ^= GTK_RBNODE_IS_PARENT;
4810 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4813 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4817 gtk_tree_view_calc_size (GtkTreeView *tree_view,
4825 GtkTreeViewColumn *column;
4827 gint vertical_separator;
4829 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4831 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4834 while (temp->left != tree->nil)
4840 /* Do stuff with node */
4841 for (list = tree_view->priv->columns; list; list = list->next)
4843 gint height = 0, width = 0;
4844 column = list->data;
4846 if (!column->visible)
4849 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4850 gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4851 max_height = MAX (max_height, vertical_separator + height);
4853 /* FIXME: I'm getting the width of all nodes here. )-: */
4854 if (column->dirty == FALSE)
4857 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4861 if (gtk_tree_view_is_expander_column (tree_view, column) &&
4862 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4863 _gtk_tree_view_column_set_width (column,
4864 MAX (column->width, depth * tree_view->priv->tab_offset + width));
4866 _gtk_tree_view_column_set_width (column, MAX (column->width, width));
4869 _gtk_rbtree_node_set_height (tree, temp, max_height);
4871 if (temp->children != NULL &&
4872 gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4873 gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
4874 temp = _gtk_rbtree_next (tree, temp);
4876 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4880 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
4885 GtkTreeViewColumn *column;
4887 gboolean retval = FALSE;
4893 for (list = tree_view->priv->columns; list; list = list->next)
4896 column = list->data;
4897 if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4899 if (!column->visible)
4902 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4906 gtk_tree_view_column_cell_get_size (column,
4908 &width, &tmpheight);
4909 *height = MAX (*height, tmpheight);
4913 gtk_tree_view_column_cell_get_size (column,
4917 if (gtk_tree_view_is_expander_column (tree_view, column) &&
4918 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4920 if (depth * tree_view->priv->tab_offset + width > column->width)
4922 column->dirty = TRUE;
4928 if (width > column->width)
4930 column->dirty = TRUE;
4940 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
4945 GtkRBNode *temp = tree->root;
4946 GtkTreeViewColumn *column;
4949 gboolean is_all_dirty;
4951 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4953 while (temp->left != tree->nil)
4958 TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
4959 is_all_dirty = TRUE;
4960 for (list = tree_view->priv->columns; list; list = list->next)
4962 column = list->data;
4963 if (column->dirty == FALSE)
4965 is_all_dirty = FALSE;
4973 gtk_tree_view_discover_dirty_iter (tree_view,
4977 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
4978 temp->children != NULL)
4979 gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
4980 temp = _gtk_rbtree_next (tree, temp);
4982 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4987 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
4990 gboolean dirty = FALSE;
4992 GtkTreeViewColumn *column;
4995 if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
4996 tree_view->priv->model)
4997 gtk_tree_view_setup_model (tree_view);
4999 for (list = tree_view->priv->columns; list; list = list->next)
5001 column = list->data;
5005 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5010 w = MAX (w, column->button->requisition.width);
5012 _gtk_tree_view_column_set_width (column, w);
5020 if (tree_view->priv->model == NULL)
5023 path = gtk_tree_path_new_root ();
5024 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
5026 gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
5027 _gtk_tree_view_update_size (tree_view);
5030 gtk_tree_path_free (path);
5032 for (list = tree_view->priv->columns; list; list = list->next)
5034 column = list->data;
5035 column->dirty = FALSE;
5039 /* Make sure the node is visible vertically */
5041 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
5047 /* We process updates because we want to clear old selected items when we scroll.
5048 * if this is removed, we get a "selection streak" at the bottom. */
5049 if (GTK_WIDGET_REALIZED (tree_view))
5050 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
5052 offset = _gtk_rbtree_node_find_offset (tree, node);
5054 /* we reverse the order, b/c in the unusual case of the
5055 * node's height being taller then the visible area, we'd rather
5056 * have the node flush to the top
5058 if (offset + GTK_RBNODE_GET_HEIGHT (node) >
5059 tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
5060 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5061 offset + GTK_RBNODE_GET_HEIGHT (node) -
5062 tree_view->priv->vadjustment->page_size);
5063 if (offset < tree_view->priv->vadjustment->value)
5064 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5069 /* This function could be more efficient.
5070 * I'll optimize it if profiling seems to imply that
5074 _gtk_tree_view_find_path (GtkTreeView *tree_view,
5079 GtkRBTree *tmp_tree;
5080 GtkRBNode *tmp_node, *last;
5083 path = gtk_tree_path_new ();
5085 g_return_val_if_fail (node != NULL, path);
5086 g_return_val_if_fail (node != tree->nil, path);
5088 count = 1 + node->left->count;
5091 tmp_node = node->parent;
5095 while (tmp_node != tmp_tree->nil)
5097 if (tmp_node->right == last)
5098 count += 1 + tmp_node->left->count;
5100 tmp_node = tmp_node->parent;
5102 gtk_tree_path_prepend_index (path, count - 1);
5103 last = tmp_tree->parent_node;
5104 tmp_tree = tmp_tree->parent_tree;
5107 count = 1 + last->left->count;
5108 tmp_node = last->parent;
5114 /* Returns TRUE if we ran out of tree before finding the path.
5117 _gtk_tree_view_find_node (GtkTreeView *tree_view,
5122 GtkRBNode *tmpnode = NULL;
5123 GtkRBTree *tmptree = tree_view->priv->tree;
5124 gint *indices = gtk_tree_path_get_indices (path);
5125 gint depth = gtk_tree_path_get_depth (path);
5135 if (tmptree == NULL)
5141 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5149 tmptree = tmpnode->children;
5155 gtk_tree_view_is_expander_column (GtkTreeView *tree_view,
5156 GtkTreeViewColumn *column)
5160 if (tree_view->priv->expander_column != NULL)
5162 if (tree_view->priv->expander_column == column)
5168 for (list = tree_view->priv->columns; list; list = list->next)
5169 if (((GtkTreeViewColumn *)list->data)->visible)
5171 if (list && list->data == column)
5178 gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
5181 GtkMovementStep step,
5185 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
5187 GTK_TYPE_ENUM, step,
5188 GTK_TYPE_INT, count);
5190 gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
5192 GTK_TYPE_ENUM, step,
5193 GTK_TYPE_INT, count);
5195 if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
5198 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
5200 GTK_TYPE_ENUM, step,
5201 GTK_TYPE_INT, count);
5203 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
5205 GTK_TYPE_ENUM, step,
5206 GTK_TYPE_INT, count);
5210 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
5215 gint retval = FALSE;
5218 g_return_val_if_fail (node != NULL, FALSE);
5223 GtkRBTree *new_tree;
5224 GtkRBNode *new_node;
5226 new_tree = node->children;
5227 new_node = new_tree->root;
5229 while (new_node && new_node->left != new_tree->nil)
5230 new_node = new_node->left;
5232 g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE);
5233 retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
5236 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
5238 gtk_tree_model_unref_node (model, iter);
5239 node = _gtk_rbtree_next (tree, node);
5241 while (gtk_tree_model_iter_next (model, iter));
5247 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
5256 while (node && node->left != tree->nil)
5259 g_return_val_if_fail (node != NULL, FALSE);
5260 path = _gtk_tree_view_find_path (tree_view, tree, node);
5261 gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
5263 retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
5264 gtk_tree_path_free (path);
5270 gtk_tree_view_set_column_drag_info (GtkTreeView *tree_view,
5271 GtkTreeViewColumn *column)
5273 GtkTreeViewColumn *left_column;
5274 GtkTreeViewColumn *cur_column = NULL;
5275 GtkTreeViewColumnReorder *reorder;
5280 /* We want to precalculate the motion list such that we know what column slots
5285 /* First, identify all possible drop spots */
5286 tmp_list = tree_view->priv->columns;
5290 g_assert (tmp_list);
5292 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5293 tmp_list = tmp_list->next;
5295 if (cur_column->visible == FALSE)
5298 /* If it's not the column moving and func tells us to skip over the column, we continue. */
5299 if (left_column != column && cur_column != column &&
5300 tree_view->priv->column_drop_func &&
5301 ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5303 left_column = cur_column;
5306 reorder = g_new (GtkTreeViewColumnReorder, 1);
5307 reorder->left_column = left_column;
5308 left_column = reorder->right_column = cur_column;
5310 tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5313 /* Add the last one */
5314 if (tree_view->priv->column_drop_func == NULL ||
5315 ((left_column != column) &&
5316 (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
5318 reorder = g_new (GtkTreeViewColumnReorder, 1);
5319 reorder->left_column = left_column;
5320 reorder->right_column = NULL;
5321 tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5324 /* We quickly check to see if it even makes sense to reorder columns. */
5325 /* If there is nothing that can be moved, then we return */
5327 if (tree_view->priv->column_drag_info == NULL)
5330 /* We know there are always 2 slots possbile, as you can always return column. */
5331 /* If that's all there is, return */
5332 if (tree_view->priv->column_drag_info->next->next == NULL &&
5333 ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
5334 ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
5336 for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5337 g_free (tmp_list->data);
5338 g_list_free (tree_view->priv->column_drag_info);
5339 tree_view->priv->column_drag_info = NULL;
5342 /* We fill in the ranges for the columns, now that we've isolated them */
5343 left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5345 for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5347 reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
5349 reorder->left_align = left;
5350 if (tmp_list->next != NULL)
5352 g_assert (tmp_list->next->data);
5353 left = reorder->right_align = (reorder->right_column->button->allocation.x +
5354 reorder->right_column->button->allocation.width +
5355 ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
5361 gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
5362 reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5368 _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
5369 GtkTreeViewColumn *column)
5371 GdkEvent send_event;
5372 GtkAllocation allocation;
5373 gint x, y, width, height;
5375 g_return_if_fail (tree_view->priv->column_drag_info == NULL);
5377 gtk_tree_view_set_column_drag_info (tree_view, column);
5379 if (tree_view->priv->column_drag_info == NULL)
5382 if (tree_view->priv->drag_window == NULL)
5384 GdkWindowAttr attributes;
5385 guint attributes_mask;
5387 attributes.window_type = GDK_WINDOW_CHILD;
5388 attributes.wclass = GDK_INPUT_OUTPUT;
5389 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
5390 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
5391 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
5392 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
5394 tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
5397 gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
5400 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5401 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5403 gtk_grab_remove (column->button);
5405 send_event.crossing.type = GDK_LEAVE_NOTIFY;
5406 send_event.crossing.send_event = TRUE;
5407 send_event.crossing.window = column->button->window;
5408 send_event.crossing.subwindow = NULL;
5409 send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
5410 send_event.crossing.time = GDK_CURRENT_TIME;
5412 gtk_propagate_event (column->button, &send_event);
5414 send_event.button.type = GDK_BUTTON_RELEASE;
5415 send_event.button.window = GDK_ROOT_PARENT ();
5416 send_event.button.send_event = TRUE;
5417 send_event.button.time = GDK_CURRENT_TIME;
5418 send_event.button.x = -1;
5419 send_event.button.y = -1;
5420 send_event.button.axes = NULL;
5421 send_event.button.state = 0;
5422 send_event.button.button = 1;
5423 send_event.button.device = gdk_core_pointer;
5424 send_event.button.x_root = 0;
5425 send_event.button.y_root = 0;
5427 gtk_propagate_event (column->button, &send_event);
5429 gdk_window_move_resize (tree_view->priv->drag_window,
5430 column->button->allocation.x,
5431 column->button->allocation.y + column->button->allocation.height,
5432 column->button->allocation.width,
5433 column->button->allocation.height);
5434 gdk_window_reparent (column->button->window, tree_view->priv->drag_window, 0, 0);
5435 tree_view->priv->drag_column_x = column->button->allocation.x;
5436 allocation = column->button->allocation;
5438 gtk_widget_size_allocate (column->button, &allocation);
5439 gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
5441 tree_view->priv->drag_column = column;
5442 gdk_window_show (tree_view->priv->drag_window);
5444 gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
5445 gdk_window_get_size (tree_view->priv->header_window, &width, &height);
5447 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5448 while (gtk_events_pending ())
5449 gtk_main_iteration ();
5451 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
5452 gdk_pointer_grab (tree_view->priv->drag_window,
5454 GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
5455 NULL, NULL, GDK_CURRENT_TIME);
5456 gdk_keyboard_grab (tree_view->priv->drag_window,
5463 gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
5466 GdkRectangle *clip_rect)
5470 if (!GTK_WIDGET_REALIZED (tree_view))
5474 rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
5476 rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
5477 rect.height = BACKGROUND_HEIGHT (node);
5481 GdkRectangle new_rect;
5483 gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
5485 gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
5489 gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
5494 gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
5496 GdkRectangle *clip_rect)
5498 GtkRBTree *tree = NULL;
5499 GtkRBNode *node = NULL;
5501 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5504 gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
5507 /* x and y are the mouse position
5510 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
5520 gint vertical_separator;
5521 gint expander_height;
5523 gtk_widget_style_get (GTK_WIDGET (tree_view),
5524 "vertical_separator", &vertical_separator,
5525 "expander_height", &expander_height,
5528 if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
5531 widget = GTK_WIDGET (tree_view);
5533 gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
5536 area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
5537 area.width = tree_view->priv->tab_offset - 2;
5538 area.height = CELL_HEIGHT (node, vertical_separator);
5540 if (node == tree_view->priv->button_pressed_node)
5542 if (x >= area.x && x <= (area.x + area.width) &&
5543 y >= area.y && y <= (area.y + area.height))
5544 state = GTK_STATE_ACTIVE;
5546 state = GTK_STATE_NORMAL;
5550 if (node == tree_view->priv->prelight_node &&
5551 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
5552 state = GTK_STATE_PRELIGHT;
5554 state = GTK_STATE_NORMAL;
5557 gtk_paint_expander (widget->style,
5558 tree_view->priv->bin_window,
5564 (area.y + (area.height - expander_height) / 2 - (area.height + 1) % 2),
5565 node->children != NULL);
5570 _gtk_tree_view_update_col_width (GtkTreeView *tree_view)
5572 GList *list, *last_column;
5573 GtkTreeViewColumn *column;
5576 for (last_column = g_list_last (tree_view->priv->columns);
5578 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
5579 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
5580 last_column = last_column->prev)
5583 if (last_column == NULL)
5586 for (list = tree_view->priv->columns; list != last_column; list = list->next)
5588 column = GTK_TREE_VIEW_COLUMN (list->data);
5589 if (! column->visible)
5592 width += column->width;
5593 column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
5595 column = GTK_TREE_VIEW_COLUMN (last_column->data);
5596 column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
5600 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
5603 GtkTreePath *cursor_path;
5605 if ((tree_view->priv->tree == NULL) ||
5606 (! GTK_WIDGET_REALIZED (tree_view)))
5609 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
5610 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5613 if (tree_view->priv->cursor)
5614 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5616 if (cursor_path == NULL)
5618 GtkTreePath *tmp_path = gtk_tree_path_new_root ();
5619 /* FIXME: Get the first one visible!!! */
5620 if (tree_view->priv->cursor)
5621 gtk_tree_row_reference_free (tree_view->priv->cursor);
5623 tree_view->priv->cursor =
5624 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
5625 cursor_path = tmp_path;
5628 if (tree_view->priv->selection->type == GTK_TREE_SELECTION_SINGLE)
5629 gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
5631 gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
5632 gtk_tree_path_free (cursor_path);
5636 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
5639 GtkRBTree *cursor_tree = NULL;
5640 GtkRBNode *cursor_node = NULL;
5641 GtkRBTree *new_cursor_tree = NULL;
5642 GtkRBNode *new_cursor_node = NULL;
5643 GtkTreePath *cursor_path = NULL;
5646 if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
5649 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5650 _gtk_tree_view_find_node (tree_view, cursor_path,
5651 &cursor_tree, &cursor_node);
5652 gtk_tree_path_free (cursor_path);
5655 _gtk_rbtree_prev_full (cursor_tree, cursor_node,
5656 &new_cursor_tree, &new_cursor_node);
5658 _gtk_rbtree_next_full (cursor_tree, cursor_node,
5659 &new_cursor_tree, &new_cursor_node);
5661 if (new_cursor_node)
5663 cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
5664 gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
5665 gtk_tree_path_free (cursor_path);
5669 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5672 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5676 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
5679 GtkRBTree *cursor_tree = NULL;
5680 GtkRBNode *cursor_node = NULL;
5681 GtkTreePath *cursor_path = NULL;
5683 gint vertical_separator;
5685 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
5686 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5688 /* This is sorta weird. Focus in should give us a cursor */
5691 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5692 _gtk_tree_view_find_node (tree_view, cursor_path,
5693 &cursor_tree, &cursor_node);
5695 gtk_tree_path_free (cursor_path);
5697 g_return_if_fail (cursor_node != NULL);
5699 y = CELL_FIRST_PIXEL (tree_view, cursor_tree, cursor_node, vertical_separator);
5700 y += count * tree_view->priv->vadjustment->page_size;
5701 y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower, (gint)tree_view->priv->vadjustment->upper - vertical_separator);
5703 _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
5704 cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5705 g_return_if_fail (cursor_path != NULL);
5706 gtk_tree_view_real_set_cursor (tree_view,
5712 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
5715 GtkRBTree *cursor_tree = NULL;
5716 GtkRBNode *cursor_node = NULL;
5717 GtkTreePath *cursor_path = NULL;
5719 g_print ("gtk_tree_view_move_cursor_left_right\n");
5721 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
5722 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5726 _gtk_tree_view_find_node (tree_view, cursor_path,
5727 &cursor_tree, &cursor_node);
5728 gtk_tree_path_free (cursor_path);
5734 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
5737 GtkRBTree *cursor_tree;
5738 GtkRBNode *cursor_node;
5741 g_return_if_fail (tree_view->priv->tree != NULL);
5745 cursor_tree = tree_view->priv->tree;
5746 cursor_node = cursor_tree->root;
5747 while (cursor_node && cursor_node->left != cursor_tree->nil)
5748 cursor_node = cursor_node->left;
5752 cursor_tree = tree_view->priv->tree;
5753 cursor_node = cursor_tree->root;
5756 while (cursor_node && cursor_node->right != cursor_tree->nil)
5757 cursor_node = cursor_node->right;
5758 if (cursor_node->children == NULL)
5761 cursor_tree = cursor_node->children;
5762 cursor_node = cursor_tree->root;
5767 path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5768 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5772 FALSE?GDK_SHIFT_MASK:0);
5774 gtk_tree_row_reference_free (tree_view->priv->cursor);
5775 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
5776 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5780 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view)
5782 GtkRBTree *cursor_tree = NULL;
5783 GtkRBNode *cursor_node = NULL;
5784 GtkTreePath *cursor_path = NULL;
5787 if (tree_view->priv->cursor)
5788 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5790 if (cursor_path == NULL)
5793 _gtk_tree_view_find_node (tree_view, cursor_path,
5794 &cursor_tree, &cursor_node);
5795 if (cursor_tree == NULL)
5798 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5804 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5806 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5807 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5808 gtk_tree_path_free (cursor_path);
5812 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
5814 GtkRBTree *cursor_tree = NULL;
5815 GtkRBNode *cursor_node = NULL;
5816 GtkTreePath *cursor_path = NULL;
5819 if (tree_view->priv->cursor)
5820 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5822 if (cursor_path == NULL)
5825 _gtk_tree_view_find_node (tree_view, cursor_path,
5826 &cursor_tree, &cursor_node);
5827 if (cursor_tree == NULL)
5830 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5836 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5838 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5839 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5840 gtk_tree_path_free (cursor_path);
5846 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
5851 GtkTreePath *cursor_path = NULL;
5854 if (tree_view->priv->cursor)
5855 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5857 if (cursor_path == NULL)
5861 gtk_tree_view_expand_row (tree_view, cursor_path, open_all);
5863 gtk_tree_view_collapse_row (tree_view, cursor_path);
5865 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5866 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5867 gtk_tree_path_free (cursor_path);
5871 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
5873 GtkRBTree *cursor_tree = NULL;
5874 GtkRBNode *cursor_node = NULL;
5875 GtkTreePath *cursor_path = NULL;
5878 if (tree_view->priv->cursor)
5879 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5881 if (cursor_path == NULL)
5884 _gtk_tree_view_find_node (tree_view, cursor_path,
5885 &cursor_tree, &cursor_node);
5886 if (cursor_tree == NULL)
5889 if (cursor_tree->parent_node)
5891 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5892 cursor_node = cursor_tree->parent_node;
5893 cursor_tree = cursor_tree->parent_tree;
5895 gtk_tree_path_up (cursor_path);
5896 gtk_tree_row_reference_free (tree_view->priv->cursor);
5897 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
5898 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5905 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5907 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5908 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5909 gtk_tree_path_free (cursor_path);
5913 _gtk_tree_view_update_size (GtkTreeView *tree_view)
5917 GtkTreeViewColumn *column;
5918 gint vertical_separator;
5921 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5923 if (tree_view->priv->model == NULL)
5925 tree_view->priv->width = 0;
5926 tree_view->priv->height = 0;
5927 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5932 for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
5934 column = list->data;
5935 if (!column->visible)
5937 width += TREE_VIEW_COLUMN_WIDTH (column);
5940 if (tree_view->priv->tree == NULL)
5943 height = tree_view->priv->tree->root->offset + vertical_separator;
5945 if (tree_view->priv->width != width)
5947 tree_view->priv->width = width;
5948 tree_view->priv->hadjustment->upper = width;
5949 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
5952 if (tree_view->priv->height != height)
5954 tree_view->priv->height = height;
5955 tree_view->priv->vadjustment->upper = tree_view->priv->height;
5956 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
5959 if (GTK_WIDGET_REALIZED (tree_view))
5961 gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
5962 gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
5964 _gtk_tree_view_update_col_width (tree_view);
5967 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5970 /* this function returns the new width of the column being resized given
5971 * the column and x position of the cursor; the x cursor position is passed
5972 * in as a pointer and automagicly corrected if it's beyond min/max limits
5975 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
5979 GtkTreeViewColumn *column;
5982 /* first translate the x position from widget->window
5983 * to clist->clist_window
5986 column = g_list_nth (tree_view->priv->columns, i)->data;
5987 width = *x - column->button->allocation.x;
5989 /* Clamp down the value */
5990 if (column->min_width == -1)
5991 width = MAX (column->button->requisition.width,
5994 width = MAX (column->min_width,
5996 if (column->max_width != -1)
5997 width = MIN (width, column->max_width != -1);
5998 *x = column->button->allocation.x + width;
6006 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
6007 GtkTreeView *tree_view)
6009 if (GTK_WIDGET_REALIZED (tree_view))
6011 gdk_window_move (tree_view->priv->bin_window,
6012 - tree_view->priv->hadjustment->value,
6013 - tree_view->priv->vadjustment->value);
6014 gdk_window_move (tree_view->priv->header_window,
6015 - tree_view->priv->hadjustment->value,
6018 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6019 gdk_window_process_updates (tree_view->priv->header_window, TRUE);
6029 * gtk_tree_view_new:
6031 * Creates a new #GtkTreeView widget.
6033 * Return value: A newly created #GtkTreeView widget.
6036 gtk_tree_view_new (void)
6038 GtkTreeView *tree_view;
6040 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6042 return GTK_WIDGET (tree_view);
6046 * gtk_tree_view_new_with_model:
6047 * @model: the model.
6049 * Creates a new #GtkTreeView widget with the model initialized to @model.
6051 * Return value: A newly created #GtkTreeView widget.
6054 gtk_tree_view_new_with_model (GtkTreeModel *model)
6056 GtkTreeView *tree_view;
6058 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6059 gtk_tree_view_set_model (tree_view, model);
6061 return GTK_WIDGET (tree_view);
6068 * gtk_tree_view_get_model:
6069 * @tree_view: a #GtkTreeView
6071 * Returns the model the the #GtkTreeView is based on. Returns NULL if the
6074 * Return value: A #GtkTreeModel, or NULL if none is currently being used.
6077 gtk_tree_view_get_model (GtkTreeView *tree_view)
6079 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6081 return tree_view->priv->model;
6085 * gtk_tree_view_set_model:
6086 * @tree_view: A #GtkTreeNode.
6087 * @model: The model.
6089 * Sets the model for a #GtkTreeView. If the @tree_view already has a model
6090 * set, it will remove it before setting the new model. If @model is NULL, then
6091 * it will unset the old model.
6094 gtk_tree_view_set_model (GtkTreeView *tree_view,
6095 GtkTreeModel *model)
6097 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6099 if (model == tree_view->priv->model)
6103 g_object_ref (model);
6105 if (tree_view->priv->model != NULL)
6107 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
6109 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6110 G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
6112 gtk_tree_view_range_changed, tree_view);
6113 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6114 G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
6116 gtk_tree_view_inserted, tree_view);
6117 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6118 G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
6120 gtk_tree_view_has_child_toggled, tree_view);
6121 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6122 G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
6124 gtk_tree_view_deleted, tree_view);
6125 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6126 G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
6128 gtk_tree_view_reordered, tree_view);
6129 if (tree_view->priv->tree)
6130 _gtk_rbtree_free (tree_view->priv->tree);
6133 if (tree_view->priv->drag_dest_row)
6134 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
6136 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
6137 g_object_unref (tree_view->priv->model);
6140 tree_view->priv->model = model;
6144 tree_view->priv->tree = NULL;
6145 if (GTK_WIDGET_REALIZED (tree_view))
6146 _gtk_tree_view_update_size (tree_view);
6148 else if (GTK_WIDGET_REALIZED (tree_view))
6150 gtk_tree_view_setup_model (tree_view);
6151 _gtk_tree_view_update_size (tree_view);
6154 g_object_notify (G_OBJECT (tree_view), "model");
6158 * gtk_tree_view_get_selection:
6159 * @tree_view: A #GtkTreeView.
6161 * Gets the #GtkTreeSelection associated with @tree_view.
6163 * Return value: A #GtkTreeSelection object.
6166 gtk_tree_view_get_selection (GtkTreeView *tree_view)
6168 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6170 return tree_view->priv->selection;
6174 * gtk_tree_view_get_hadjustment:
6175 * @tree_view: A #GtkTreeView
6177 * Gets the #GtkAdjustment currently being used for the horizontal aspect.
6179 * Return value: A #GtkAdjustment object, or NULL if none is currently being
6183 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
6185 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6187 if (tree_view->priv->hadjustment == NULL)
6188 gtk_tree_view_set_hadjustment (tree_view, NULL);
6190 return tree_view->priv->hadjustment;
6194 * gtk_tree_view_set_hadjustment:
6195 * @tree_view: A #GtkTreeView
6196 * @adjustment: The #GtkAdjustment to set, or NULL
6198 * Sets the #GtkAdjustment for the current horizontal aspect.
6201 gtk_tree_view_set_hadjustment (GtkTreeView *tree_view,
6202 GtkAdjustment *adjustment)
6204 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6206 gtk_tree_view_set_adjustments (tree_view,
6208 tree_view->priv->vadjustment);
6210 g_object_notify (G_OBJECT (tree_view), "hadjustment");
6214 * gtk_tree_view_get_vadjustment:
6215 * @tree_view: A #GtkTreeView
6217 * Gets the #GtkAdjustment currently being used for the vertical aspect.
6219 * Return value: A #GtkAdjustment object, or NULL if none is currently being
6223 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
6225 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6227 if (tree_view->priv->vadjustment == NULL)
6228 gtk_tree_view_set_vadjustment (tree_view, NULL);
6230 return tree_view->priv->vadjustment;
6234 * gtk_tree_view_set_vadjustment:
6235 * @tree_view: A #GtkTreeView
6236 * @adjustment: The #GtkAdjustment to set, or NULL
6238 * Sets the #GtkAdjustment for the current vertical aspect.
6241 gtk_tree_view_set_vadjustment (GtkTreeView *tree_view,
6242 GtkAdjustment *adjustment)
6244 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6246 gtk_tree_view_set_adjustments (tree_view,
6247 tree_view->priv->hadjustment,
6250 g_object_notify (G_OBJECT (tree_view), "vadjustment");
6253 /* Column and header operations */
6256 * gtk_tree_view_get_headers_visible:
6257 * @tree_view: A #GtkTreeView.
6259 * Returns TRUE if the headers on the @tree_view are visible.
6261 * Return value: Whether the headers are visible or not.
6264 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
6266 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6268 return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6272 * gtk_tree_view_set_headers_visible:
6273 * @tree_view: A #GtkTreeView.
6274 * @headers_visible: TRUE if the headers are visible
6276 * Sets the the visibility state of the headers.
6279 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
6280 gboolean headers_visible)
6284 GtkTreeViewColumn *column;
6286 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6288 headers_visible = !! headers_visible;
6290 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
6293 if (headers_visible)
6294 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6296 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6298 if (GTK_WIDGET_REALIZED (tree_view))
6300 gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
6301 if (headers_visible)
6303 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
6305 if (GTK_WIDGET_MAPPED (tree_view))
6306 gtk_tree_view_map_buttons (tree_view);
6310 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
6312 for (list = tree_view->priv->columns; list; list = list->next)
6314 column = list->data;
6315 gtk_widget_unmap (column->button);
6317 gdk_window_hide (tree_view->priv->header_window);
6321 tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
6322 tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
6323 tree_view->priv->vadjustment->lower = 0;
6324 tree_view->priv->vadjustment->upper = tree_view->priv->height;
6325 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
6327 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6329 g_object_notify (G_OBJECT (tree_view), "headers_visible");
6334 * gtk_tree_view_columns_autosize:
6335 * @tree_view: A #GtkTreeView.
6337 * Resizes all columns to their optimal width.
6340 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
6342 gboolean dirty = FALSE;
6344 GtkTreeViewColumn *column;
6346 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6348 for (list = tree_view->priv->columns; list; list = list->next)
6350 column = list->data;
6351 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
6353 column->dirty = TRUE;
6358 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6362 * gtk_tree_view_set_headers_clickable:
6363 * @tree_view: A #GtkTreeView.
6364 * @setting: TRUE if the columns are clickable.
6366 * Allow the column title buttons to be clicked.
6369 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
6374 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6375 g_return_if_fail (tree_view->priv->model != NULL);
6377 for (list = tree_view->priv->columns; list; list = list->next)
6378 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
6380 g_object_notify (G_OBJECT (tree_view), "headers_clickable");
6385 * gtk_tree_view_set_rules_hint
6386 * @tree_view: a #GtkTreeView
6387 * @setting: %TRUE if the tree requires reading across rows
6389 * This function tells GTK+ that the user interface for your
6390 * application requires users to read across tree rows and associate
6391 * cells with one another. By default, GTK+ will then render the tree
6392 * with alternating row colors. <emphasis>DO NOT</emphasis> use it
6393 * just because you prefer the appearance of the ruled tree; that's a
6394 * question for the theme. Some themes will draw tree rows in
6395 * alternating colors even when rules are turned off, and users who
6396 * prefer that appearance all the time can choose those themes. You
6397 * should call this function only as a <emphasis>semantic</emphasis>
6398 * hint to the theme engine that your tree makes alternating colors
6399 * useful from a functional standpoint (since it has lots of columns,
6404 gtk_tree_view_set_rules_hint (GtkTreeView *tree_view,
6407 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6409 setting = setting != FALSE;
6411 if (tree_view->priv->has_rules != setting)
6413 tree_view->priv->has_rules = setting;
6414 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6417 g_object_notify (G_OBJECT (tree_view), "rules_hint");
6421 * gtk_tree_view_get_rules_hint
6422 * @tree_view: a #GtkTreeView
6424 * Gets the setting set by gtk_tree_view_set_rules_hint().
6426 * Return value: %TRUE if rules are useful for the user of this tree
6429 gtk_tree_view_get_rules_hint (GtkTreeView *tree_view)
6431 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6433 return tree_view->priv->has_rules;
6436 /* Public Column functions
6440 * gtk_tree_view_append_column:
6441 * @tree_view: A #GtkTreeView.
6442 * @column: The #GtkTreeViewColumn to add.
6444 * Appends @column to the list of columns.
6446 * Return value: The number of columns in @tree_view after appending.
6449 gtk_tree_view_append_column (GtkTreeView *tree_view,
6450 GtkTreeViewColumn *column)
6452 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6453 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6454 g_return_val_if_fail (column->tree_view == NULL, -1);
6456 return gtk_tree_view_insert_column (tree_view, column, -1);
6461 * gtk_tree_view_remove_column:
6462 * @tree_view: A #GtkTreeView.
6463 * @column: The #GtkTreeViewColumn to remove.
6465 * Removes @column from @tree_view.
6467 * Return value: The number of columns in @tree_view after removing.
6470 gtk_tree_view_remove_column (GtkTreeView *tree_view,
6471 GtkTreeViewColumn *column)
6473 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6474 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6475 g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
6477 _gtk_tree_view_column_unset_tree_view (column);
6479 if (tree_view->priv->focus_column == column)
6480 tree_view->priv->focus_column = NULL;
6482 tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
6483 tree_view->priv->n_columns--;
6485 if (GTK_WIDGET_REALIZED (tree_view))
6489 _gtk_tree_view_column_unrealize_button (column);
6490 for (list = tree_view->priv->columns; list; list = list->next)
6492 column = GTK_TREE_VIEW_COLUMN (list->data);
6493 if (column->visible)
6494 column->dirty = TRUE;
6497 if (tree_view->priv->n_columns == 0 &&
6498 gtk_tree_view_get_headers_visible (tree_view))
6499 gdk_window_hide (tree_view->priv->header_window);
6501 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6504 g_object_unref (G_OBJECT (column));
6505 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6507 return tree_view->priv->n_columns;
6511 * gtk_tree_view_insert_column:
6512 * @tree_view: A #GtkTreeView.
6513 * @column: The #GtkTreeViewColumn to be inserted.
6514 * @position: The position to insert @column in.
6516 * This inserts the @column into the @tree_view at @position. If @position is
6517 * -1, then the column is inserted at the end.
6519 * Return value: The number of columns in @tree_view after insertion.
6522 gtk_tree_view_insert_column (GtkTreeView *tree_view,
6523 GtkTreeViewColumn *column,
6526 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6527 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6528 g_return_val_if_fail (column->tree_view == NULL, -1);
6530 g_object_ref (G_OBJECT (column));
6532 if (tree_view->priv->n_columns == 0 &&
6533 GTK_WIDGET_REALIZED (tree_view) &&
6534 gtk_tree_view_get_headers_visible (tree_view))
6536 gdk_window_show (tree_view->priv->header_window);
6539 tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
6541 tree_view->priv->n_columns++;
6543 _gtk_tree_view_column_set_tree_view (column, tree_view);
6545 if (GTK_WIDGET_REALIZED (tree_view))
6549 _gtk_tree_view_column_realize_button (column);
6551 for (list = tree_view->priv->columns; list; list = list->next)
6553 column = GTK_TREE_VIEW_COLUMN (list->data);
6554 if (column->visible)
6555 column->dirty = TRUE;
6557 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6560 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6562 return tree_view->priv->n_columns;
6566 * gtk_tree_view_insert_column_with_attributes:
6567 * @tree_view: A #GtkTreeView
6568 * @position: The position to insert the new column in.
6569 * @title: The title to set the header to.
6570 * @cell: The #GtkCellRenderer.
6571 * @Varargs: A NULL terminated list of attributes.
6573 * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
6574 * @position. If @position is -1, then the newly created column is inserted at
6575 * the end. The column is initialized with the attributes given.
6577 * Return value: The number of columns in @tree_view after insertion.
6580 gtk_tree_view_insert_column_with_attributes (GtkTreeView *tree_view,
6583 GtkCellRenderer *cell,
6586 GtkTreeViewColumn *column;
6591 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6593 column = gtk_tree_view_column_new ();
6595 gtk_tree_view_column_set_title (column, title);
6596 gtk_tree_view_column_set_cell_renderer (column, cell);
6598 va_start (args, cell);
6600 attribute = va_arg (args, gchar *);
6602 while (attribute != NULL)
6604 column_id = va_arg (args, gint);
6605 gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
6606 attribute = va_arg (args, gchar *);
6611 gtk_tree_view_insert_column (tree_view, column, position);
6612 g_object_unref (column);
6614 return tree_view->priv->n_columns;
6618 * gtk_tree_view_insert_column_with_data_func:
6619 * @tree_view: a #GtkTreeView
6620 * @position: Position to insert, -1 for append
6621 * @title: column title
6622 * @cell: cell renderer for column
6623 * @func: function to set attributes of cell renderer
6624 * @data: data for @func
6625 * @dnotify: destroy notifier for @data
6627 * Convenience function that inserts a new column into the #GtkTreeView
6628 * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
6629 * attributes (normally using data from the model). See also
6630 * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_set_cell_renderer().
6632 * Return value: number of columns in the tree view post-insert
6635 gtk_tree_view_insert_column_with_data_func (GtkTreeView *tree_view,
6638 GtkCellRenderer *cell,
6639 GtkTreeCellDataFunc func,
6641 GDestroyNotify dnotify)
6643 GtkTreeViewColumn *column;
6645 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6647 column = gtk_tree_view_column_new ();
6649 gtk_tree_view_column_set_title (column, title);
6650 gtk_tree_view_column_set_cell_renderer (column, cell);
6651 gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
6653 gtk_tree_view_insert_column (tree_view, column, position);
6655 g_object_unref (column);
6657 return tree_view->priv->n_columns;
6661 * gtk_tree_view_get_column:
6662 * @tree_view: A #GtkTreeView.
6663 * @n: The position of the column, counting from 0.
6665 * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
6667 * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
6671 gtk_tree_view_get_column (GtkTreeView *tree_view,
6674 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6676 if (n < 0 || n >= tree_view->priv->n_columns)
6679 if (tree_view->priv->columns == NULL)
6682 return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
6686 * gtk_tree_view_get_columns:
6687 * @tree_view: A #GtkTreeView
6689 * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
6690 * The returned list must be freed with g_list_free ().
6692 * Return value: A list of #GtkTreeViewColumn s
6695 gtk_tree_view_get_columns (GtkTreeView *tree_view)
6697 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6699 return g_list_copy (tree_view->priv->columns);
6703 * gtk_tree_view_move_column_after:
6704 * @tree_view: A #GtkTreeView
6705 * @column: The #GtkTreeViewColumn to be moved.
6706 * @base_column: The #GtkTreeViewColumn to be moved relative to.
6708 * Moves @column to be after to @base_column. If @base_column is NULL, then
6709 * @column is placed in the first position.
6712 gtk_tree_view_move_column_after (GtkTreeView *tree_view,
6713 GtkTreeViewColumn *column,
6714 GtkTreeViewColumn *base_column)
6716 GList *column_list_el, *base_el = NULL;
6718 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6720 column_list_el = g_list_find (tree_view->priv->columns, column);
6721 g_return_if_fail (column_list_el != NULL);
6725 base_el = g_list_find (tree_view->priv->columns, base_column);
6726 g_return_if_fail (base_el != NULL);
6729 if (column_list_el->prev == base_el)
6732 tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
6733 if (base_el == NULL)
6735 column_list_el->prev = NULL;
6736 column_list_el->next = tree_view->priv->columns;
6737 if (column_list_el->next)
6738 column_list_el->next->prev = column_list_el;
6739 tree_view->priv->columns = column_list_el;
6743 column_list_el->prev = base_el;
6744 column_list_el->next = base_el->next;
6745 if (column_list_el->next)
6746 column_list_el->next->prev = column_list_el;
6747 base_el->next = column_list_el;
6750 if (GTK_WIDGET_REALIZED (tree_view))
6752 //gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6753 _gtk_tree_view_update_size (tree_view);
6754 gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view));
6757 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6761 * gtk_tree_view_set_expander_column:
6762 * @tree_view: A #GtkTreeView
6763 * @column: NULL, or the column to draw the expander arrow at.
6765 * Sets the column to draw the expander arrow at. It must be in @tree_view. If
6766 * @column is %NULL, then the expander arrow is fixed at the first column.
6769 gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
6770 GtkTreeViewColumn *column)
6772 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6774 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6776 if (tree_view->priv->expander_column != column)
6782 /* Confirm that column is in tree_view */
6783 for (list = tree_view->priv->columns; list; list = list->next)
6784 if (list->data == column)
6786 g_return_if_fail (list != NULL);
6789 tree_view->priv->expander_column = column;
6790 g_object_notify (G_OBJECT (tree_view), "expander_column");
6795 * gtk_tree_view_get_expander_column:
6796 * @tree_view: A #GtkTreeView
6798 * Returns the column that is the current expander column. This
6799 * column has the expander arrow drawn next to it.
6801 * Return value: The expander column.
6804 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
6806 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6808 return tree_view->priv->expander_column;
6813 * gtk_tree_view_set_column_drag_function:
6814 * @tree_view: A #GtkTreeView.
6815 * @func: A function to determine which columns are reorderable, or NULL.
6816 * @user_data: User data to be passed to @func, or NULL
6817 * @destroy: Destroy notifier for @user_data, or NULL
6819 * Sets a user function for determining where a column may be dropped when
6820 * dragged. This function is called on every column pair in turn at the
6821 * beginning of a column drag to determine where a drop can take place. The
6822 * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
6823 * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
6824 * @user_data. If either of the #GtkTreeViewColumn arguments for the drop spot
6825 * are NULL, then they indicate an edge. If @func is set to be NULL, then
6826 * @tree_view reverts to the default behavior of allowing all columns to be
6827 * dropped everywhere.
6830 gtk_tree_view_set_column_drag_function (GtkTreeView *tree_view,
6831 GtkTreeViewColumnDropFunc func,
6833 GtkDestroyNotify destroy)
6835 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6837 if (tree_view->priv->column_drop_func_data_destroy)
6838 (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
6840 tree_view->priv->column_drop_func = func;
6841 tree_view->priv->column_drop_func_data = user_data;
6842 tree_view->priv->column_drop_func_data_destroy = destroy;
6846 * gtk_tree_view_scroll_to_point:
6847 * @tree_view: a #GtkTreeView
6848 * @tree_x: X coordinate of new top-left pixel of visible area
6849 * @tree_y: Y coordinate of new top-left pixel of visible area
6851 * Scrolls the tree view such that the top-left corner of the visible
6852 * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
6853 * in tree window coordinates. The @tree_view must be realized before
6854 * this function is called. If it isn't, you probably want ot be
6855 * using gtk_tree_view_scroll_to_cell.
6858 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
6862 GtkAdjustment *hadj;
6863 GtkAdjustment *vadj;
6865 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6866 g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
6868 hadj = tree_view->priv->hadjustment;
6869 vadj = tree_view->priv->vadjustment;
6871 gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
6872 gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
6876 * gtk_tree_view_scroll_to_cell
6877 * @tree_view: A #GtkTreeView.
6878 * @path: The path of the row to move to.
6879 * @column: The #GtkTreeViewColumn to move horizontally to.
6880 * @row_align: The vertical alignment of the row specified by @path.
6881 * @col_align: The horizontal alignment of the column specified by @column.
6883 * Moves the alignments of @tree_view to the position specified by
6884 * @column and @path. If @column is NULL, then no horizontal
6885 * scrolling occurs. Likewise, if @path is NULL no vertical scrolling
6886 * occurs. @row_align determines where the row is placed, and
6887 * @col_align determines where @column is placed. Both are expected
6888 * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
6889 * right/bottom alignment, 0.5 means center.
6892 gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
6894 GtkTreeViewColumn *column,
6898 GdkRectangle cell_rect;
6899 GdkRectangle vis_rect;
6900 gint dest_x, dest_y;
6902 /* FIXME work on unmapped/unrealized trees? maybe implement when
6903 * we do incremental reflow for trees
6906 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6907 g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
6908 g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
6909 g_return_if_fail (path != NULL || column != NULL);
6911 row_align = CLAMP (row_align, 0.0, 1.0);
6912 col_align = CLAMP (col_align, 0.0, 1.0);
6914 if (! GTK_WIDGET_REALIZED (tree_view))
6917 tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
6919 tree_view->priv->scroll_to_column = column;
6920 tree_view->priv->scroll_to_row_align = row_align;
6921 tree_view->priv->scroll_to_col_align = col_align;
6926 gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
6927 gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
6929 dest_x = vis_rect.x;
6930 dest_y = vis_rect.y;
6934 dest_x = cell_rect.x +
6935 cell_rect.width * row_align -
6936 vis_rect.width * row_align;
6941 dest_y = cell_rect.y +
6942 cell_rect.height * col_align -
6943 vis_rect.height * col_align;
6946 gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
6951 * gtk_tree_view_row_activated:
6952 * @tree_view: A #GtkTreeView
6953 * @path: The #GtkTreePath to be activated.
6954 * @column: The #GtkTreeViewColumn to be activated.
6956 * Activates the cell determined by @path and @column.
6959 gtk_tree_view_row_activated (GtkTreeView *tree_view,
6961 GtkTreeViewColumn *column)
6963 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6965 /* FIXME: Actually activate the path internally, not just emit the signal */
6966 /* g_warning ("FIXME: Actually activate the path internally, not just emit the signal\n"); */
6967 g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
6972 gtk_tree_view_expand_all_helper (GtkRBTree *tree,
6976 GtkTreeView *tree_view = data;
6979 _gtk_rbtree_traverse (node->children,
6980 node->children->root,
6982 gtk_tree_view_expand_all_helper,
6984 else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
6990 node->children = _gtk_rbtree_new ();
6991 node->children->parent_tree = tree;
6992 node->children->parent_node = node;
6993 path = _gtk_tree_view_find_path (tree_view, tree, node);
6994 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6995 gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
6996 gtk_tree_view_build_tree (tree_view,
6999 gtk_tree_path_get_depth (path) + 1,
7001 GTK_WIDGET_REALIZED (tree_view));
7002 gtk_tree_path_free (path);
7007 * gtk_tree_view_expand_all:
7008 * @tree_view: A #GtkTreeView.
7010 * Recursively expands all nodes in the @tree_view.
7013 gtk_tree_view_expand_all (GtkTreeView *tree_view)
7015 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7016 g_return_if_fail (tree_view->priv->tree != NULL);
7018 _gtk_rbtree_traverse (tree_view->priv->tree,
7019 tree_view->priv->tree->root,
7021 gtk_tree_view_expand_all_helper,
7024 _gtk_tree_view_update_size (tree_view);
7028 gtk_tree_view_collapse_all_helper (GtkRBTree *tree,
7037 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
7039 node->children->root);
7040 gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
7043 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
7046 gtk_tree_path_get_depth (path));
7048 /* Ensure we don't have a dangling pointer to a dead node */
7049 ensure_unprelighted (GTK_TREE_VIEW (data));
7051 _gtk_rbtree_remove (node->children);
7052 gtk_tree_path_free (path);
7057 * gtk_tree_view_collapse_all:
7058 * @tree_view: A #GtkTreeView.
7060 * Recursively collapses all visible, expanded nodes in @tree_view.
7063 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
7065 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7066 g_return_if_fail (tree_view->priv->tree != NULL);
7068 _gtk_rbtree_traverse (tree_view->priv->tree,
7069 tree_view->priv->tree->root,
7071 gtk_tree_view_collapse_all_helper,
7074 if (GTK_WIDGET_MAPPED (tree_view))
7075 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7078 /* FIXME the bool return values for expand_row and collapse_row are
7079 * not analagous; they should be TRUE if the row had children and
7080 * was not already in the requested state.
7085 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
7098 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7099 if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
7102 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
7107 node->children = _gtk_rbtree_new ();
7108 node->children->parent_tree = tree;
7109 node->children->parent_node = node;
7111 gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
7113 gtk_tree_view_build_tree (tree_view,
7116 gtk_tree_path_get_depth (path) + 1,
7118 GTK_WIDGET_REALIZED (tree_view));
7120 if (GTK_WIDGET_MAPPED (tree_view))
7122 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7123 _gtk_tree_view_update_size (tree_view);
7126 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
7133 * gtk_tree_view_expand_row:
7134 * @tree_view: a #GtkTreeView
7135 * @path: path to a row
7136 * @open_all: whether to recursively expand, or just expand immediate children
7138 * Opens the row so its children are visible
7140 * Return value: %TRUE if the row existed and had children
7143 gtk_tree_view_expand_row (GtkTreeView *tree_view,
7150 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7151 g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
7152 g_return_val_if_fail (path != NULL, FALSE);
7154 if (_gtk_tree_view_find_node (tree_view,
7160 return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all);
7164 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
7170 GtkTreeIter children;
7173 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7175 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
7180 TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
7182 gtk_tree_view_discover_dirty (tree_view,
7185 gtk_tree_path_get_depth (path));
7187 /* Ensure we don't have a dangling pointer to a dead node */
7188 ensure_unprelighted (tree_view);
7190 if (tree_view->priv->destroy_count_func)
7192 gint child_count = 0;
7194 _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
7195 (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
7198 if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
7199 g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0);
7200 _gtk_rbtree_remove (node->children);
7202 if (GTK_WIDGET_MAPPED (tree_view))
7204 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7205 _gtk_tree_view_update_size (tree_view);
7208 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7210 GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7212 if (gtk_tree_path_is_ancestor (path, cursor_path))
7214 gtk_tree_row_reference_free (tree_view->priv->cursor);
7215 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7216 tree_view->priv->model,
7219 gtk_tree_path_free (cursor_path);
7222 if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
7224 GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
7225 if (gtk_tree_path_is_ancestor (path, anchor_path))
7227 gtk_tree_row_reference_free (tree_view->priv->anchor);
7228 tree_view->priv->anchor = NULL;
7230 gtk_tree_path_free (anchor_path);
7234 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
7240 * gtk_tree_view_collapse_row:
7241 * @tree_view: a #GtkTreeView
7242 * @path: path to a row in the @tree_view
7244 * Collapses a row (hides its child rows, if they exist.)
7246 * Return value: %TRUE if the row was collapsed.
7249 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
7255 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7256 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7257 g_return_val_if_fail (path != NULL, FALSE);
7259 if (_gtk_tree_view_find_node (tree_view,
7265 if (node->children == NULL)
7268 return gtk_tree_view_real_collapse_row (tree_view, path, tree, node);
7272 gtk_tree_view_map_expanded_rows_helper (GtkTreeView *tree_view,
7275 GtkTreeViewMappingFunc func,
7283 if (tree == NULL || tree->root == NULL)
7288 indices = gtk_tree_path_get_indices (path);
7289 depth = gtk_tree_path_get_depth (path);
7291 while (node && node->left != tree->nil)
7298 gtk_tree_path_append_index (path, 0);
7299 gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
7300 gtk_tree_path_up (path);
7301 (* func) (tree_view, path, user_data);
7304 indices[depth -1] = i;
7305 node = _gtk_rbtree_next (tree, node);
7310 * gtk_tree_view_map_expanded_rows:
7311 * @tree_view: A #GtkTreeView
7312 * @func: A function to be called
7313 * @data: User data to be passed to the function.
7315 * Calls @func on all expanded rows.
7318 gtk_tree_view_map_expanded_rows (GtkTreeView *tree_view,
7319 GtkTreeViewMappingFunc func,
7324 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7325 g_return_if_fail (func != NULL);
7327 path = gtk_tree_path_new_root ();
7329 gtk_tree_view_map_expanded_rows_helper (tree_view,
7330 tree_view->priv->tree,
7331 path, func, user_data);
7333 gtk_tree_path_free (path);
7337 * gtk_tree_view_row_expanded:
7338 * @tree_view: A #GtkTreeView.
7339 * @path: A #GtkTreePath to test expansion state.
7341 * Returns TRUE if the node pointed to by @path is expanded in @tree_view.
7343 * Return value: TRUE if #path is expanded.
7346 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
7352 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7353 g_return_val_if_fail (path != NULL, FALSE);
7355 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7360 return (node->children != NULL);
7363 static GtkTargetEntry row_targets[] = {
7364 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7369 * gtk_tree_view_get_reorderable:
7370 * @tree_view: a #GtkTreeView
7372 * Retrieves whether the user can reorder the tree via drag-and-drop. See
7373 * gtk_tree_view_set_reorderable().
7375 * Return value: %TRUE if the tree can be reordered.
7378 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
7380 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7382 return tree_view->priv->reorderable;
7386 * gtk_tree_view_set_reorderable:
7387 * @tree_view: A #GtkTreeView.
7388 * @reorderable: TRUE, if the tree can be reordered.
7390 * This function is a convenience function to allow you to reorder models that
7391 * support the #GtkDragSourceIface and the #GtkDragDestIface. Both
7392 * #GtkTreeStore and #GtkListStore support these. If @reorderable is TRUE, then
7393 * the user can reorder the model by dragging and dropping columns. The
7394 * developer will can listen to these changes by connecting to the model's
7397 * This function does not give you any degree of control over the order -- any
7398 * reorderering is allowed. If more control is needed, you should probably
7399 * handle drag and drop manually.
7402 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
7403 gboolean reorderable)
7405 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7407 if (tree_view->priv->reorderable == (reorderable?TRUE:FALSE))
7410 gtk_tree_view_set_rows_drag_source (tree_view,
7413 G_N_ELEMENTS (row_targets),
7416 gtk_tree_view_set_rows_drag_dest (tree_view,
7418 G_N_ELEMENTS (row_targets),
7422 g_object_notify (G_OBJECT (tree_view), "reorderable");
7426 gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
7428 gboolean clear_and_select)
7430 GtkRBTree *tree = NULL;
7431 GtkRBNode *node = NULL;
7433 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7435 GtkTreePath *cursor_path;
7436 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7437 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7438 gtk_tree_path_free (cursor_path);
7440 gtk_tree_row_reference_free (tree_view->priv->cursor);
7442 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7443 tree_view->priv->model,
7445 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7449 if (clear_and_select && !tree_view->priv->in_free_motion)
7450 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7452 tree_view->priv->in_extended_selection?GDK_SHIFT_MASK:0);
7453 gtk_tree_view_clamp_node_visible (tree_view, tree, node);
7454 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
7458 * gtk_tree_view_set_cursor:
7459 * @tree_view: A #GtkTreeView
7460 * @path: A #GtkTreePath
7462 * Sets the current keyboard focus to be at @path, and selects it. This is
7463 * useful when you want to focus the user's attention on a particular row. If
7464 * you want to give the user keyboard focus in the tree_view, you should use
7465 * this function to set the correct path, and gtk_widget_grab_focus (GTK_WIDGET
7466 * (tree_view)) to actually give focus to the @tree_view.
7469 gtk_tree_view_set_cursor (GtkTreeView *tree_view,
7472 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7473 g_return_if_fail (path != NULL);
7475 gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
7480 * gtk_tree_view_get_path_at_pos:
7481 * @tree_view: A #GtkTreeView.
7482 * @window: The #GdkWindow to check against.
7483 * @x: The x position to be identified.
7484 * @y: The y position to be identified.
7485 * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
7486 * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
7487 * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
7488 * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
7490 * Finds the path at the point (@x, @y) relative to @window. If @window is
7491 * NULL, then the point is found relative to the widget coordinates. This
7492 * function is expected to be called after an event, with event->window being
7493 * passed in as @window. It is primarily for things like popup menus. If @path
7494 * is non-NULL, then it will be filled with the #GtkTreePath at that point.
7495 * This path should be freed with #gtk_tree_path_free. If @column is non-NULL,
7496 * then it will be filled with the column at that point. @cell_x and @cell_y
7497 * return the coordinates relative to the cell background (i.e. the
7498 * background_area passed to gtk_cell_renderer_render()). This function only
7499 * works if @tree_view is realized.
7501 * Return value: TRUE if a row exists at that coordinate.
7504 gtk_tree_view_get_path_at_pos (GtkTreeView *tree_view,
7509 GtkTreeViewColumn **column,
7517 g_return_val_if_fail (tree_view != NULL, FALSE);
7518 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7519 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
7522 g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
7529 if (x > tree_view->priv->hadjustment->upper)
7535 if (column || cell_x)
7537 GtkTreeViewColumn *tmp_column;
7538 GtkTreeViewColumn *last_column = NULL;
7540 gint remaining_x = x;
7541 gboolean found = FALSE;
7543 for (list = tree_view->priv->columns; list; list = list->next)
7545 tmp_column = list->data;
7547 if (tmp_column->visible == FALSE)
7550 last_column = tmp_column;
7551 if (remaining_x <= tmp_column->width)
7556 *column = tmp_column;
7559 *cell_x = remaining_x;
7563 remaining_x -= tmp_column->width;
7569 *column = last_column;
7572 *cell_x = last_column->width + remaining_x;
7578 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7579 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
7584 if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
7587 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7588 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
7599 *path = _gtk_tree_view_find_path (tree_view, tree, node);
7606 * gtk_tree_view_get_cell_area:
7607 * @tree_view: a #GtkTreeView
7608 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7609 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7610 * @rect: rectangle to fill with cell rect
7612 * Fills the bounding rectangle in tree window coordinates for the cell at the
7613 * row specified by @path and the column specified by @column. If @path is
7614 * %NULL, the y and height fields of the rectangle will be filled with 0. If
7615 * @column is %NULL, the x and width fields will be filled with 0. The sum of
7616 * all cell rects does not cover the entire tree; there are extra pixels in
7617 * between rows, for example. The returned rectangle is equivalent to the
7618 * @cell_area passed to gtk_cell_renderer_render(). This function is only valid
7619 * if #tree_view is realized.
7622 gtk_tree_view_get_cell_area (GtkTreeView *tree_view,
7624 GtkTreeViewColumn *column,
7627 GtkRBTree *tree = NULL;
7628 GtkRBNode *node = NULL;
7629 gint vertical_separator;
7631 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7632 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7633 g_return_if_fail (rect != NULL);
7635 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
7644 /* Get vertical coords */
7646 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7650 g_warning (G_STRLOC": no row corresponding to path");
7654 /* Remember that the rbtree stores node height including the vertical
7655 * separator, see comment at top of file.
7657 rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
7659 rect->height = CELL_HEIGHT (node, vertical_separator);
7666 gtk_tree_view_get_cell_xrange (tree_view, tree, column, &rect->x, &x2);
7667 rect->width = x2 - rect->x;
7672 * gtk_tree_view_get_background_area:
7673 * @tree_view: a #GtkTreeView
7674 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7675 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7676 * @rect: rectangle to fill with cell background rect
7678 * Fills the bounding rectangle in tree window coordinates for the
7679 * cell at the row specified by @path and the column specified by
7680 * @column. If @path is %NULL, the y and height fields of the
7681 * rectangle will be filled with 0. If @column is %NULL, the x and
7682 * width fields will be filled with 0. The returned rectangle is
7683 * equivalent to the @background_area passed to
7684 * gtk_cell_renderer_render(). These background areas tile to cover
7685 * the entire tree window (except for the area used for header
7686 * buttons). Contrast with the cell_area, returned by
7687 * gtk_tree_view_get_cell_area(), which returns only the cell itself,
7688 * excluding surrounding borders and the tree expander area.
7692 gtk_tree_view_get_background_area (GtkTreeView *tree_view,
7694 GtkTreeViewColumn *column,
7697 GtkRBTree *tree = NULL;
7698 GtkRBNode *node = NULL;
7700 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7701 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7702 g_return_if_fail (rect != NULL);
7711 /* Get vertical coords */
7713 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7717 g_warning (G_STRLOC": no row corresponding to path");
7721 rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
7723 rect->height = BACKGROUND_HEIGHT (node);
7730 gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
7731 rect->width = x2 - rect->x;
7736 * gtk_tree_view_get_visible_rect:
7737 * @tree_view: a #GtkTreeView
7738 * @visible_rect: rectangle to fill
7740 * Fills @visible_rect with the currently-visible region of the
7741 * buffer, in tree coordinates. Convert to widget coordinates with
7742 * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
7743 * 0,0 for row 0 of the tree, and cover the entire scrollable area of
7747 gtk_tree_view_get_visible_rect (GtkTreeView *tree_view,
7748 GdkRectangle *visible_rect)
7752 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7754 widget = GTK_WIDGET (tree_view);
7758 visible_rect->x = tree_view->priv->hadjustment->value;
7759 visible_rect->y = tree_view->priv->vadjustment->value;
7760 visible_rect->width = widget->allocation.width;
7761 visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7766 * gtk_tree_view_widget_to_tree_coords:
7767 * @tree_view: a #GtkTreeView
7768 * @wx: widget X coordinate
7769 * @wy: widget Y coordinate
7770 * @tx: return location for tree X coordinate
7771 * @ty: return location for tree Y coordinate
7773 * Converts widget coordinates to coordinates for the
7774 * tree window (the full scrollable area of the tree).
7778 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
7784 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7788 *tx = wx + tree_view->priv->hadjustment->value;
7793 *ty = wy + tree_view->priv->vadjustment->value;
7798 * gtk_tree_view_tree_to_widget_coords:
7799 * @tree_view: a #GtkTreeView
7800 * @tx: tree X coordinate
7801 * @ty: tree Y coordinate
7802 * @wx: return location for widget X coordinate
7803 * @wy: return location for widget Y coordinate
7805 * Converts tree coordinates (coordinates in full scrollable area of the tree)
7806 * to widget coordinates.
7810 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
7816 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7820 *wx = tx - tree_view->priv->hadjustment->value;
7825 *wy = ty - tree_view->priv->vadjustment->value;
7831 gtk_tree_view_set_rows_drag_source (GtkTreeView *tree_view,
7832 GdkModifierType start_button_mask,
7833 const GtkTargetEntry *targets,
7835 GdkDragAction actions,
7836 GtkTreeViewDraggableFunc row_draggable_func,
7839 TreeViewDragInfo *di;
7841 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7843 di = ensure_info (tree_view);
7844 clear_source_info (di);
7846 di->start_button_mask = start_button_mask;
7847 di->source_target_list = gtk_target_list_new (targets, n_targets);
7848 di->source_actions = actions;
7850 if (row_draggable_func)
7852 di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
7854 g_closure_ref (di->row_draggable_closure);
7855 g_closure_sink (di->row_draggable_closure);
7858 di->source_set = TRUE;
7862 gtk_tree_view_set_rows_drag_dest (GtkTreeView *tree_view,
7863 const GtkTargetEntry *targets,
7865 GdkDragAction actions,
7866 GtkTreeViewDroppableFunc location_droppable_func,
7869 TreeViewDragInfo *di;
7871 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7873 gtk_drag_dest_set (GTK_WIDGET (tree_view),
7879 di = ensure_info (tree_view);
7880 clear_dest_info (di);
7883 di->dest_target_list = gtk_target_list_new (targets, n_targets);
7885 if (location_droppable_func)
7887 di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
7889 g_closure_ref (di->location_droppable_closure);
7890 g_closure_sink (di->location_droppable_closure);
7893 di->dest_set = TRUE;
7897 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
7899 TreeViewDragInfo *di;
7901 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7903 di = get_info (tree_view);
7909 clear_source_info (di);
7910 di->source_set = FALSE;
7913 if (!di->dest_set && !di->source_set)
7914 remove_info (tree_view);
7919 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
7921 TreeViewDragInfo *di;
7923 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7925 di = get_info (tree_view);
7931 gtk_drag_dest_unset (GTK_WIDGET (tree_view));
7932 clear_dest_info (di);
7933 di->dest_set = FALSE;
7936 if (!di->dest_set && !di->source_set)
7937 remove_info (tree_view);
7942 gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
7944 GtkTreeViewDropPosition pos)
7946 GtkTreePath *current_dest;
7947 /* Note; this function is exported to allow a custom DND
7948 * implementation, so it can't touch TreeViewDragInfo
7951 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7953 current_dest = NULL;
7955 if (tree_view->priv->drag_dest_row)
7956 current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7960 gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
7961 gtk_tree_path_free (current_dest);
7964 if (tree_view->priv->drag_dest_row)
7965 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
7967 tree_view->priv->drag_dest_pos = pos;
7971 tree_view->priv->drag_dest_row =
7972 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
7973 gtk_tree_view_queue_draw_path (tree_view, path, NULL);
7976 tree_view->priv->drag_dest_row = NULL;
7980 gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
7982 GtkTreeViewDropPosition *pos)
7984 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7988 if (tree_view->priv->drag_dest_row)
7989 *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7995 *pos = tree_view->priv->drag_dest_pos;
7999 gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
8003 GtkTreeViewDropPosition *pos)
8006 gdouble offset_into_row;
8010 GtkTreeViewColumn *column = NULL;
8011 GtkTreePath *tmp_path = NULL;
8013 /* Note; this function is exported to allow a custom DND
8014 * implementation, so it can't touch TreeViewDragInfo
8017 g_return_val_if_fail (tree_view != NULL, FALSE);
8018 g_return_val_if_fail (drag_x >= 0, FALSE);
8019 g_return_val_if_fail (drag_y >= 0, FALSE);
8020 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
8026 if (tree_view->priv->tree == NULL)
8029 /* remember that drag_x and drag_y are in widget coords, convert to tree window */
8031 gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
8034 /* If in the top quarter of a row, we drop before that row; if
8035 * in the bottom quarter, drop after that row; if in the middle,
8036 * and the row has children, drop into the row.
8039 if (!gtk_tree_view_get_path_at_pos (tree_view,
8040 tree_view->priv->bin_window,
8048 gtk_tree_view_get_background_area (tree_view, tmp_path, column,
8051 offset_into_row = cell_y;
8056 gtk_tree_path_free (tmp_path);
8060 quarter = cell.height / 4.0;
8064 if (offset_into_row < quarter)
8066 *pos = GTK_TREE_VIEW_DROP_BEFORE;
8068 else if (offset_into_row < quarter * 2)
8070 *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
8072 else if (offset_into_row < quarter * 3)
8074 *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
8078 *pos = GTK_TREE_VIEW_DROP_AFTER;
8087 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
8089 * gtk_tree_view_create_row_drag_icon:
8090 * @tree_view: a #GtkTreeView
8091 * @path: a #GtkTreePath in @tree_view
8093 * Creates a GdkPixmap representation of the row at @path. This image is used
8096 * Return value: a newly allocatdd pixmap of the drag icon.
8099 gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
8107 GdkRectangle background_area;
8110 /* start drawing inside the black outline */
8112 GdkDrawable *drawable;
8113 gint bin_window_width;
8115 widget = GTK_WIDGET (tree_view);
8117 depth = gtk_tree_path_get_depth (path);
8119 _gtk_tree_view_find_node (tree_view,
8127 if (!gtk_tree_model_get_iter (tree_view->priv->model,
8134 background_area.y = y;
8135 background_area.height = BACKGROUND_HEIGHT (node);
8137 gdk_drawable_get_size (tree_view->priv->bin_window,
8138 &bin_window_width, NULL);
8140 drawable = gdk_pixmap_new (tree_view->priv->bin_window,
8141 bin_window_width + 2,
8142 background_area.height + 2,
8145 gdk_draw_rectangle (drawable,
8146 widget->style->base_gc [GTK_WIDGET_STATE (widget)],
8149 bin_window_width + 2,
8150 background_area.height + 2);
8152 gdk_draw_rectangle (drawable,
8153 widget->style->black_gc,
8156 bin_window_width + 1,
8157 background_area.height + 1);
8159 for (list = tree_view->priv->columns; list; list = list->next)
8161 GtkTreeViewColumn *column = list->data;
8162 GdkRectangle cell_area;
8163 gint vertical_separator;
8165 if (!column->visible)
8168 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter);
8170 background_area.x = cell_offset;
8171 background_area.width = column->displayed_width;
8173 cell_area = background_area;
8175 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
8176 cell_area.y += vertical_separator / 2;
8177 cell_area.height -= vertical_separator;
8179 if (gtk_tree_view_is_expander_column (tree_view, column) &&
8180 TREE_VIEW_DRAW_EXPANDERS(tree_view))
8182 cell_area.x += depth * tree_view->priv->tab_offset;
8183 cell_area.width -= depth * tree_view->priv->tab_offset;
8186 if (gtk_tree_view_column_cell_is_visible (column))
8187 gtk_tree_view_column_cell_render (column,
8194 cell_offset += column->displayed_width;
8202 * gtk_tree_view_set_destroy_count_func:
8203 * @tree_view: A #GtkTreeView
8204 * @func: Function to be called when a view row is destroyed, or NULL
8205 * @data: User data to be passed to @func, or NULL
8206 * @destroy: Destroy notifier for @data, or NULL
8208 * This function should almost never be used. It is meant for private use by
8209 * ATK for determining the number of visible children that are removed when the
8210 * user collapses a row, or a row is deleted.
8213 gtk_tree_view_set_destroy_count_func (GtkTreeView *tree_view,
8214 GtkTreeDestroyCountFunc func,
8216 GtkDestroyNotify destroy)
8218 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8220 if (tree_view->priv->destroy_count_destroy)
8221 (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
8223 tree_view->priv->destroy_count_func = func;
8224 tree_view->priv->destroy_count_data = data;
8225 tree_view->priv->destroy_count_destroy = destroy;