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 (widget != NULL);
1095 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1097 tree_view = GTK_TREE_VIEW (widget);
1099 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
1100 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1102 /* Make the main, clipping window */
1103 attributes.window_type = GDK_WINDOW_CHILD;
1104 attributes.x = widget->allocation.x;
1105 attributes.y = widget->allocation.y;
1106 attributes.width = widget->allocation.width;
1107 attributes.height = widget->allocation.height;
1108 attributes.wclass = GDK_INPUT_OUTPUT;
1109 attributes.visual = gtk_widget_get_visual (widget);
1110 attributes.colormap = gtk_widget_get_colormap (widget);
1111 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1113 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1115 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1116 &attributes, attributes_mask);
1117 gdk_window_set_user_data (widget->window, widget);
1119 /* Make the window for the tree */
1122 attributes.width = tree_view->priv->width;
1123 attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
1124 attributes.event_mask = GDK_EXPOSURE_MASK |
1126 GDK_POINTER_MOTION_MASK |
1127 GDK_ENTER_NOTIFY_MASK |
1128 GDK_LEAVE_NOTIFY_MASK |
1129 GDK_BUTTON_PRESS_MASK |
1130 GDK_BUTTON_RELEASE_MASK |
1131 gtk_widget_get_events (widget);
1133 tree_view->priv->bin_window = gdk_window_new (widget->window,
1134 &attributes, attributes_mask);
1135 gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1137 /* Make the column header window */
1140 attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1141 attributes.height = tree_view->priv->header_height;
1142 attributes.event_mask = (GDK_EXPOSURE_MASK |
1144 GDK_BUTTON_PRESS_MASK |
1145 GDK_BUTTON_RELEASE_MASK |
1146 GDK_KEY_PRESS_MASK |
1147 GDK_KEY_RELEASE_MASK) |
1148 gtk_widget_get_events (widget);
1150 tree_view->priv->header_window = gdk_window_new (widget->window,
1151 &attributes, attributes_mask);
1152 gdk_window_set_user_data (tree_view->priv->header_window, widget);
1155 values.foreground = (widget->style->white.pixel==0 ?
1156 widget->style->black:widget->style->white);
1157 values.function = GDK_XOR;
1158 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1159 tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
1164 /* Add them all up. */
1165 widget->style = gtk_style_attach (widget->style, widget->window);
1166 gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1167 gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1168 gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1170 tmp_list = tree_view->priv->children;
1173 GtkTreeViewChild *child = tmp_list->data;
1174 tmp_list = tmp_list->next;
1176 gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1179 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1180 _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1182 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1184 if (tree_view->priv->scroll_to_path != NULL ||
1185 tree_view->priv->scroll_to_column != NULL)
1187 gtk_tree_view_scroll_to_cell (tree_view,
1188 tree_view->priv->scroll_to_path,
1189 tree_view->priv->scroll_to_column,
1190 tree_view->priv->scroll_to_row_align,
1191 tree_view->priv->scroll_to_col_align);
1192 if (tree_view->priv->scroll_to_path)
1194 gtk_tree_path_free (tree_view->priv->scroll_to_path);
1195 tree_view->priv->scroll_to_path = NULL;
1197 tree_view->priv->scroll_to_column = NULL;
1202 gtk_tree_view_unrealize (GtkWidget *widget)
1204 GtkTreeView *tree_view;
1207 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1209 tree_view = GTK_TREE_VIEW (widget);
1211 if (tree_view->priv->scroll_timeout != 0)
1213 gtk_timeout_remove (tree_view->priv->scroll_timeout);
1214 tree_view->priv->scroll_timeout = 0;
1217 if (tree_view->priv->open_dest_timeout != 0)
1219 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
1220 tree_view->priv->open_dest_timeout = 0;
1223 for (list = tree_view->priv->columns; list; list = list->next)
1224 _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1226 gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
1227 gdk_window_destroy (tree_view->priv->bin_window);
1228 tree_view->priv->bin_window = NULL;
1230 gdk_window_set_user_data (tree_view->priv->header_window, NULL);
1231 gdk_window_destroy (tree_view->priv->header_window);
1232 tree_view->priv->header_window = NULL;
1234 if (tree_view->priv->drag_window)
1236 gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
1237 gdk_window_destroy (tree_view->priv->drag_window);
1238 tree_view->priv->drag_window = NULL;
1241 if (tree_view->priv->drag_highlight_window)
1243 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
1244 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1245 tree_view->priv->drag_highlight_window = NULL;
1248 if (tree_view->priv->cursor_drag)
1250 gdk_cursor_destroy (tree_view->priv->cursor_drag);
1251 tree_view->priv->cursor_drag = NULL;
1254 if (tree_view->priv->xor_gc)
1256 gdk_gc_destroy (tree_view->priv->xor_gc);
1257 tree_view->priv->xor_gc = NULL;
1260 /* GtkWidget::unrealize destroys children and widget->window */
1261 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1262 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1265 /* GtkWidget::size_request helper */
1267 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
1271 tree_view->priv->header_height = 1;
1273 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
1275 for (list = tree_view->priv->columns; list; list = list->next)
1277 GtkRequisition requisition;
1278 GtkTreeViewColumn *column = list->data;
1280 if (column->button == NULL)
1283 column = list->data;
1285 gtk_widget_size_request (column->button, &requisition);
1287 _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
1288 tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1294 gtk_tree_view_size_request (GtkWidget *widget,
1295 GtkRequisition *requisition)
1297 GtkTreeView *tree_view;
1300 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1302 tree_view = GTK_TREE_VIEW (widget);
1304 requisition->width = tree_view->priv->width;
1305 requisition->height = tree_view->priv->height + tree_view->priv->header_height;
1307 tmp_list = tree_view->priv->children;
1311 GtkTreeViewChild *child = tmp_list->data;
1312 GtkRequisition child_requisition;
1314 tmp_list = tmp_list->next;
1316 if (GTK_WIDGET_VISIBLE (child->widget))
1317 gtk_widget_size_request (child->widget, &child_requisition);
1320 gtk_tree_view_size_request_buttons (tree_view);
1323 /* GtkWidget::size_allocate helper */
1325 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
1327 GtkTreeView *tree_view;
1329 GtkTreeViewColumn *column;
1330 GtkAllocation allocation;
1333 tree_view = GTK_TREE_VIEW (widget);
1336 allocation.height = tree_view->priv->header_height;
1338 for (list = tree_view->priv->columns; list != NULL; list = list->next)
1340 column = list->data;
1342 if (!column->visible)
1345 allocation.x = width;
1346 allocation.width = column->displayed_width;
1347 width += column->width;
1348 gtk_widget_size_allocate (column->button, &allocation);
1351 gdk_window_move_resize (column->window,
1352 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
1354 TREE_VIEW_DRAG_WIDTH, allocation.height);
1359 gtk_tree_view_size_allocate (GtkWidget *widget,
1360 GtkAllocation *allocation)
1363 GtkTreeView *tree_view;
1365 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1367 widget->allocation = *allocation;
1369 tree_view = GTK_TREE_VIEW (widget);
1371 gtk_tree_view_check_dirty (tree_view);
1373 tmp_list = tree_view->priv->children;
1377 GtkAllocation allocation;
1378 GtkRequisition requisition;
1380 GtkTreeViewChild *child = tmp_list->data;
1381 tmp_list = tmp_list->next;
1383 allocation.x = child->x;
1384 allocation.y = child->y;
1385 gtk_widget_get_child_requisition (child->widget, &requisition);
1386 allocation.width = requisition.width;
1387 allocation.height = requisition.height;
1389 gtk_widget_size_allocate (child->widget, &allocation);
1392 if (GTK_WIDGET_REALIZED (widget))
1394 gdk_window_move_resize (widget->window,
1395 allocation->x, allocation->y,
1396 allocation->width, allocation->height);
1397 gdk_window_resize (tree_view->priv->header_window,
1398 MAX (tree_view->priv->width, allocation->width),
1399 tree_view->priv->header_height);
1400 if (tree_view->priv->width < allocation->width)
1401 gdk_window_resize (tree_view->priv->bin_window,
1403 tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
1405 _gtk_tree_view_update_col_width (tree_view);
1408 gtk_tree_view_size_allocate_buttons (widget);
1410 tree_view->priv->hadjustment->page_size = allocation->width;
1411 tree_view->priv->hadjustment->page_increment = allocation->width;
1412 tree_view->priv->hadjustment->step_increment = allocation->width / 10;
1413 tree_view->priv->hadjustment->lower = 0;
1414 tree_view->priv->hadjustment->upper = tree_view->priv->width;
1416 if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
1417 tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
1418 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
1420 tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
1421 tree_view->priv->vadjustment->step_increment = (tree_view->priv->vadjustment->page_size) / 10;
1422 tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
1423 tree_view->priv->vadjustment->lower = 0;
1424 tree_view->priv->vadjustment->upper = tree_view->priv->height;
1426 if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
1427 gtk_adjustment_set_value (tree_view->priv->vadjustment,
1428 MAX (tree_view->priv->height - allocation->height, 0));
1430 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
1435 gtk_tree_view_button_press (GtkWidget *widget,
1436 GdkEventButton *event)
1438 GtkTreeView *tree_view;
1440 GtkTreeViewColumn *column = NULL;
1442 GdkRectangle background_area;
1443 GdkRectangle cell_area;
1444 gint vertical_separator;
1446 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1447 g_return_val_if_fail (event != NULL, FALSE);
1449 tree_view = GTK_TREE_VIEW (widget);
1450 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
1452 if (event->window == tree_view->priv->bin_window)
1461 GtkTreeViewColumn *column = NULL;
1463 if (!GTK_WIDGET_HAS_FOCUS (widget))
1464 gtk_widget_grab_focus (widget);
1465 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1467 /* are we in an arrow? */
1468 if (tree_view->priv->prelight_node &&
1469 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1471 if (event->button == 1)
1473 gtk_grab_add (widget);
1474 tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1475 tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1476 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1477 tree_view->priv->prelight_tree,
1478 tree_view->priv->prelight_node,
1485 /* find the node that was clicked */
1486 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1487 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1488 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1490 &node) + new_y - (gint)event->y;
1493 /* We clicked in dead space */
1496 /* Get the path and the node */
1497 path = _gtk_tree_view_find_path (tree_view, tree, node);
1498 depth = gtk_tree_path_get_depth (path);
1499 background_area.y = y_offset + event->y + vertical_separator;
1500 background_area.height = GTK_RBNODE_GET_HEIGHT (node) - vertical_separator;
1501 background_area.x = 0;
1503 /* Let the column have a chance at selecting it. */
1504 for (list = tree_view->priv->columns; list; list = list->next)
1508 column = list->data;
1510 if (!column->visible)
1513 background_area.width = column->displayed_width;
1514 if (gtk_tree_view_is_expander_column (tree_view, column) &&
1515 TREE_VIEW_DRAW_EXPANDERS(tree_view))
1517 cell_area = background_area;
1518 cell_area.x += depth*tree_view->priv->tab_offset;
1519 cell_area.width -= depth*tree_view->priv->tab_offset;
1523 cell_area = background_area;
1526 if ((background_area.x > (gint) event->x) ||
1527 (background_area.y > (gint) event->y) ||
1528 (background_area.x + background_area.width <= (gint) event->x) ||
1529 (background_area.y + background_area.height <= (gint) event->y))
1531 background_area.x += background_area.width;
1535 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1536 gtk_tree_view_column_cell_set_cell_data (column,
1537 tree_view->priv->model,
1540 path_string = gtk_tree_path_to_string (path);
1542 if (gtk_tree_view_column_cell_event (column,
1548 g_free (path_string);
1549 gtk_tree_path_free (path);
1554 g_free (path_string);
1562 /* The columns didn't want the event. We handle it */
1564 /* Save press to possibly begin a drag
1566 if (tree_view->priv->pressed_button < 0)
1568 tree_view->priv->pressed_button = event->button;
1569 tree_view->priv->press_start_x = event->x;
1570 tree_view->priv->press_start_y = event->y;
1573 gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
1575 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1577 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
1579 if (node->children == NULL)
1580 gtk_tree_view_real_expand_row (tree_view, path,
1583 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1586 gtk_tree_view_row_activated (tree_view, path, column);
1589 gtk_tree_path_free (path);
1593 /* We didn't click in the window. Let's check to see if we clicked on a column resize window.
1595 for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1597 column = list->data;
1598 if (event->window == column->window &&
1599 column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE &&
1604 if (gdk_pointer_grab (column->window, FALSE,
1605 GDK_POINTER_MOTION_HINT_MASK |
1606 GDK_BUTTON1_MOTION_MASK |
1607 GDK_BUTTON_RELEASE_MASK,
1608 NULL, NULL, event->time))
1611 gtk_grab_add (widget);
1612 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1614 /* block attached dnd signal handler */
1615 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1617 gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1619 if (!GTK_WIDGET_HAS_FOCUS (widget))
1620 gtk_widget_grab_focus (widget);
1622 tree_view->priv->drag_pos = i;
1623 tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1629 /* GtkWidget::button_release_event helper */
1631 gtk_tree_view_button_release_drag_column (GtkWidget *widget,
1632 GdkEventButton *event)
1634 GtkTreeView *tree_view;
1635 GtkAllocation allocation;
1637 tree_view = GTK_TREE_VIEW (widget);
1639 allocation = tree_view->priv->drag_column->button->allocation;
1640 allocation.x = tree_view->priv->drag_column_x;
1641 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1642 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
1643 gdk_window_reparent (tree_view->priv->drag_column->button->window,
1644 tree_view->priv->header_window,
1645 tree_view->priv->drag_column_x,
1646 tree_view->priv->drag_column->button->allocation.y);
1647 gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
1649 gtk_widget_size_allocate (tree_view->priv->drag_column->button, &allocation);
1650 gtk_widget_grab_focus (tree_view->priv->drag_column->button);
1652 if (tree_view->priv->cur_reorder &&
1653 tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
1654 gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
1655 tree_view->priv->cur_reorder->left_column);
1656 tree_view->priv->drag_column = NULL;
1657 gdk_window_hide (tree_view->priv->drag_window);
1659 g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
1660 g_list_free (tree_view->priv->column_drag_info);
1661 tree_view->priv->column_drag_info = NULL;
1663 gdk_window_hide (tree_view->priv->drag_highlight_window);
1665 /* Reset our flags */
1666 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
1667 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
1672 /* GtkWidget::button_release_event helper */
1674 gtk_tree_view_button_release_column_resize (GtkWidget *widget,
1675 GdkEventButton *event)
1677 GtkTreeView *tree_view;
1683 tree_view = GTK_TREE_VIEW (widget);
1685 i = tree_view->priv->drag_pos;
1686 tree_view->priv->drag_pos = -1;
1688 /* unblock attached dnd signal handler */
1689 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1691 gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1693 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1694 gtk_widget_get_pointer (widget, &x, NULL);
1695 gtk_grab_remove (widget);
1696 gdk_pointer_ungrab (event->time);
1698 width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1699 _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1705 gtk_tree_view_button_release (GtkWidget *widget,
1706 GdkEventButton *event)
1708 GtkTreeView *tree_view;
1710 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1711 g_return_val_if_fail (event != NULL, FALSE);
1713 tree_view = GTK_TREE_VIEW (widget);
1715 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
1716 return gtk_tree_view_button_release_drag_column (widget, event);
1718 if (tree_view->priv->pressed_button == event->button)
1719 tree_view->priv->pressed_button = -1;
1721 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1722 return gtk_tree_view_button_release_column_resize (widget, event);
1724 if (tree_view->priv->button_pressed_node == NULL)
1727 if (event->button == 1)
1729 gtk_grab_remove (widget);
1730 if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1731 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1733 GtkTreePath *path = NULL;
1735 path = _gtk_tree_view_find_path (tree_view,
1736 tree_view->priv->button_pressed_tree,
1737 tree_view->priv->button_pressed_node);
1738 /* Actually activate the node */
1739 if (tree_view->priv->button_pressed_node->children == NULL)
1740 gtk_tree_view_real_expand_row (tree_view, path,
1741 tree_view->priv->button_pressed_tree,
1742 tree_view->priv->button_pressed_node,
1745 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1746 tree_view->priv->button_pressed_tree,
1747 tree_view->priv->button_pressed_node);
1748 gtk_tree_path_free (path);
1751 tree_view->priv->button_pressed_tree = NULL;
1752 tree_view->priv->button_pressed_node = NULL;
1759 /* GtkWidget::motion_event function set.
1763 coords_are_over_arrow (GtkTreeView *tree_view,
1766 /* these are in tree window coords */
1773 if (!GTK_WIDGET_REALIZED (tree_view))
1776 if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1779 arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
1781 arrow.height = BACKGROUND_HEIGHT (node);
1783 gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
1785 arrow.width = x2 - arrow.x;
1787 return (x >= arrow.x &&
1788 x < (arrow.x + arrow.height) &&
1790 y < (arrow.y + arrow.height));
1794 do_unprelight (GtkTreeView *tree_view,
1795 /* these are in tree window coords */
1799 if (tree_view->priv->prelight_node == NULL)
1802 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1804 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1805 !coords_are_over_arrow (tree_view,
1806 tree_view->priv->prelight_tree,
1807 tree_view->priv->prelight_node,
1810 /* We need to unprelight the old arrow. */
1812 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1814 gtk_tree_view_draw_arrow (tree_view,
1815 tree_view->priv->prelight_tree,
1816 tree_view->priv->prelight_node,
1822 tree_view->priv->prelight_node = NULL;
1823 tree_view->priv->prelight_tree = NULL;
1827 do_prelight (GtkTreeView *tree_view,
1830 /* these are in tree window coords */
1834 if (coords_are_over_arrow (tree_view, tree, node, x, y))
1835 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1837 tree_view->priv->prelight_node = node;
1838 tree_view->priv->prelight_tree = tree;
1840 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1844 ensure_unprelighted (GtkTreeView *tree_view)
1846 do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
1847 g_assert (tree_view->priv->prelight_node == NULL);
1852 /* Our motion arrow is either a box (in the case of the original spot)
1853 * or an arrow. It is expander_width wide.
1876 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
1878 GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
1879 GtkWidget *widget = GTK_WIDGET (tree_view);
1880 GdkBitmap *mask = NULL;
1885 gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
1886 GdkWindowAttr attributes;
1887 guint attributes_mask;
1890 reorder->left_column == tree_view->priv->drag_column ||
1891 reorder->right_column == tree_view->priv->drag_column)
1892 arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
1893 else if (reorder->left_column || reorder->right_column)
1895 GdkRectangle visible_rect;
1896 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
1897 if (reorder->left_column)
1898 x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
1900 x = reorder->right_column->button->allocation.x;
1901 if (x < visible_rect.x)
1902 arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
1903 else if (x > visible_rect.x + visible_rect.width)
1904 arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
1906 arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
1909 /* We want to draw the rectangle over the initial location. */
1910 if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
1915 if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
1918 if (tree_view->priv->drag_highlight_window)
1919 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1921 attributes.window_type = GDK_WINDOW_CHILD;
1922 attributes.wclass = GDK_INPUT_OUTPUT;
1923 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1924 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1925 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
1926 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1927 tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
1928 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
1930 width = tree_view->priv->drag_column->button->allocation.width;
1931 height = tree_view->priv->drag_column->button->allocation.height;
1932 gdk_window_move_resize (tree_view->priv->drag_highlight_window,
1933 tree_view->priv->drag_column_x, 0, width, height);
1935 mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
1936 gc = gdk_gc_new (mask);
1938 gdk_gc_set_foreground (gc, &col);
1939 gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
1941 gdk_gc_set_foreground(gc, &col);
1942 gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
1943 gdk_gc_destroy (gc);
1945 gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
1947 if (mask) gdk_pixmap_unref (mask);
1948 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
1951 else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
1956 gint expander_width;
1958 gtk_widget_style_get (widget,
1959 "expander_height", &width,
1960 "expander_width", &expander_width,
1963 /* Get x, y, width, height of arrow */
1964 if (reorder->left_column)
1966 gdk_window_get_origin (reorder->left_column->button->window, &x, &y);
1967 x += reorder->left_column->button->allocation.width - width/2;
1968 height = reorder->left_column->button->allocation.height;
1972 gdk_window_get_origin (reorder->right_column->button->window, &x, &y);
1974 height = reorder->right_column->button->allocation.height;
1976 y -= expander_width/2; /* The arrow takes up only half the space */
1977 height += expander_width;
1979 /* Create the new window */
1980 if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
1982 if (tree_view->priv->drag_highlight_window)
1983 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1985 attributes.window_type = GDK_WINDOW_TEMP;
1986 attributes.wclass = GDK_INPUT_OUTPUT;
1987 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1988 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1989 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
1990 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1991 attributes.width = width;
1992 attributes.height = height;
1993 tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
1994 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
1996 mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
1997 gc = gdk_gc_new (mask);
1999 gdk_gc_set_foreground (gc, &col);
2000 gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2002 /* Draw the 2 arrows as per above */
2004 gdk_gc_set_foreground (gc, &col);
2005 for (i = 0; i < width; i ++)
2007 if (i == (width/2 - 1))
2009 gdk_draw_line (mask, gc, i, j, i, height - j);
2010 if (i < (width/2 - 1))
2015 gdk_gc_destroy (gc);
2016 gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2018 if (mask) gdk_pixmap_unref (mask);
2021 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
2022 gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2024 else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
2025 arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2030 gint expander_height;
2032 gtk_widget_style_get (widget,
2033 "expander_height", &expander_height,
2034 "expander_width", &width,
2037 /* Get x, y, width, height of arrow */
2038 width = width/2; /* remember, the arrow only takes half the available width */
2039 gdk_window_get_origin (widget->window, &x, &y);
2040 if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2041 x += widget->allocation.width - width;
2043 if (reorder->left_column)
2044 height = reorder->left_column->button->allocation.height;
2046 height = reorder->right_column->button->allocation.height;
2048 y -= expander_height;
2049 height += 2*expander_height;
2051 /* Create the new window */
2052 if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
2053 tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2055 if (tree_view->priv->drag_highlight_window)
2056 gdk_window_destroy (tree_view->priv->drag_highlight_window);
2058 attributes.window_type = GDK_WINDOW_TEMP;
2059 attributes.wclass = GDK_INPUT_OUTPUT;
2060 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2061 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2062 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2063 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2064 attributes.width = width;
2065 attributes.height = height;
2066 tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2067 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2069 mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2070 gc = gdk_gc_new (mask);
2072 gdk_gc_set_foreground (gc, &col);
2073 gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2075 /* Draw the 2 arrows as per above */
2077 gdk_gc_set_foreground (gc, &col);
2078 j = expander_height;
2079 for (i = 0; i < width; i ++)
2082 if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
2086 gdk_draw_line (mask, gc, k, j, k, height - j);
2087 gdk_draw_line (mask, gc, k, 0, k, expander_height - j);
2088 gdk_draw_line (mask, gc, k, height, k, height - expander_height + j);
2091 gdk_gc_destroy (gc);
2092 gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2094 if (mask) gdk_pixmap_unref (mask);
2097 tree_view->priv->drag_column_window_state = arrow_type;
2098 gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2102 g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
2103 gdk_window_hide (tree_view->priv->drag_highlight_window);
2107 gdk_window_show (tree_view->priv->drag_highlight_window);
2108 gdk_window_raise (tree_view->priv->drag_highlight_window);
2112 gtk_tree_view_motion_resize_column (GtkWidget *widget,
2113 GdkEventMotion *event)
2118 if (event->is_hint || event->window != widget->window)
2119 gtk_widget_get_pointer (widget, &x, NULL);
2123 new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget),
2124 GTK_TREE_VIEW (widget)->priv->drag_pos, &x);
2125 if (x != GTK_TREE_VIEW (widget)->priv->x_drag)
2126 _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
2128 /* FIXME: Do we need to scroll */
2129 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2135 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
2137 GtkTreeViewColumnReorder *reorder = NULL;
2141 gdk_window_get_pointer (tree_view->priv->bin_window, &mouse_x, NULL, NULL);
2143 for (list = tree_view->priv->column_drag_info; list; list = list->next)
2145 reorder = (GtkTreeViewColumnReorder *) list->data;
2146 if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
2151 /* if (reorder && reorder == tree_view->priv->cur_reorder)
2154 tree_view->priv->cur_reorder = reorder;
2155 gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
2159 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
2161 GdkRectangle visible_rect;
2166 gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
2168 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2170 /* See if we are near the edge. */
2171 offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
2174 offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
2180 value = CLAMP (tree_view->priv->hadjustment->value + offset,
2181 0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
2182 gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
2189 gtk_tree_view_motion_drag_column (GtkWidget *widget,
2190 GdkEventMotion *event)
2192 GtkTreeView *tree_view = (GtkTreeView *) widget;
2193 GtkTreeViewColumn *column = tree_view->priv->drag_column;
2197 if ((column == NULL) ||
2198 (event->window != tree_view->priv->drag_window))
2201 /* Handle moving the header */
2202 gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
2203 x = CLAMP (x + (gint)event->x - column->drag_x, 0,
2204 MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
2205 gdk_window_move (tree_view->priv->drag_window, x, y);
2207 /* autoscroll, if needed */
2208 gtk_tree_view_horizontal_autoscroll (tree_view);
2209 /* Update the current reorder position and arrow; */
2210 gtk_tree_view_update_current_reorder (tree_view);
2216 gtk_tree_view_motion_bin_window (GtkWidget *widget,
2217 GdkEventMotion *event)
2219 GtkTreeView *tree_view;
2223 GtkRBTree *old_prelight_tree;
2224 GtkRBNode *old_prelight_node;
2226 tree_view = (GtkTreeView *) widget;
2228 if (tree_view->priv->tree == NULL)
2231 gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
2233 old_prelight_tree = tree_view->priv->prelight_tree;
2234 old_prelight_node = tree_view->priv->prelight_node;
2236 do_unprelight (tree_view, event->x, event->y);
2238 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2240 _gtk_rbtree_find_offset (tree_view->priv->tree,
2241 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2248 /* If we are currently pressing down a button, we don't want to prelight anything else. */
2249 if ((tree_view->priv->button_pressed_node != NULL) &&
2250 (tree_view->priv->button_pressed_node != node))
2254 do_prelight (tree_view, tree, node, event->x, new_y);
2256 if (old_prelight_node != tree_view->priv->prelight_node)
2258 if (old_prelight_node)
2259 gtk_tree_view_queue_draw_node (tree_view,
2264 if (tree_view->priv->prelight_node)
2265 gtk_tree_view_queue_draw_node (tree_view,
2266 tree_view->priv->prelight_tree,
2267 tree_view->priv->prelight_node,
2275 gtk_tree_view_motion (GtkWidget *widget,
2276 GdkEventMotion *event)
2278 GtkTreeView *tree_view;
2280 tree_view = (GtkTreeView *) widget;
2282 /* Resizing a column */
2283 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2284 return gtk_tree_view_motion_resize_column (widget, event);
2287 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2288 return gtk_tree_view_motion_drag_column (widget, event);
2290 /* Sanity check it */
2291 if (event->window == tree_view->priv->bin_window)
2292 return gtk_tree_view_motion_bin_window (widget, event);
2297 /* Draws the focus rectangle around the cursor row */
2299 gtk_tree_view_draw_focus (GtkWidget *widget)
2301 GtkTreeView *tree_view;
2302 GtkTreePath *cursor_path;
2303 GtkRBTree *tree = NULL;
2304 GtkRBNode *node = NULL;
2307 gint vertical_separator;
2309 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2311 tree_view = GTK_TREE_VIEW (widget);
2313 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2315 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
2318 if (! gtk_tree_row_reference_valid (tree_view->priv->cursor))
2321 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2323 _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
2327 gtk_tree_path_free (cursor_path);
2331 gdk_drawable_get_size (tree_view->priv->bin_window,
2336 y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2337 gdk_drawable_get_size (tree_view->priv->bin_window,
2340 height = BACKGROUND_HEIGHT (node) - 1;
2341 if (tree_view->priv->focus_column != NULL)
2345 gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
2346 gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column, tree_view->priv->model, &iter);
2348 if (gtk_tree_view_column_cell_can_focus (tree_view->priv->focus_column))
2350 GdkRectangle cell_area;
2354 cell_area.x = tree_view->priv->focus_column->button->allocation.x;
2356 cell_area.width = tree_view->priv->focus_column->displayed_width;
2357 cell_area.height = CELL_HEIGHT (node, vertical_separator);
2359 gtk_tree_view_column_cell_get_size (tree_view->priv->focus_column,
2360 &cell_area, &x_offset, &y_offset, &width, &height);
2364 x = cell_area.x + x_offset - 1;
2365 y = cell_area.y + y_offset - 1 + vertical_separator/2;
2369 gtk_paint_focus (widget->style,
2370 tree_view->priv->bin_window,
2374 x, y, width, height);
2376 gtk_tree_path_free (cursor_path);
2379 /* Warning: Very scary function.
2380 * Modify at your own risk
2383 gtk_tree_view_bin_expose (GtkWidget *widget,
2384 GdkEventExpose *event)
2386 GtkTreeView *tree_view;
2391 GtkRBNode *cursor = NULL;
2392 GtkRBTree *cursor_tree = NULL;
2393 GtkRBNode *drag_highlight = NULL;
2394 GtkRBTree *drag_highlight_tree = NULL;
2397 gint y_offset, x_offset, cell_offset;
2400 GdkRectangle background_area;
2401 GdkRectangle cell_area;
2404 gint bin_window_width;
2405 GtkTreePath *cursor_path;
2406 GtkTreePath *drag_dest_path;
2408 gint vertical_separator;
2410 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2412 tree_view = GTK_TREE_VIEW (widget);
2413 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2415 if (tree_view->priv->tree == NULL)
2418 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
2419 /* we want to account for a potential HEADER offset.
2420 * That is, if the header exists, we want to offset our event by its
2421 * height to find the right node.
2423 new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
2425 /* y_offset is the */
2427 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
2428 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2430 &node) + new_y - event->area.y;
2434 /* find the path for the node */
2435 path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
2438 gtk_tree_model_get_iter (tree_view->priv->model,
2441 depth = gtk_tree_path_get_depth (path);
2442 gtk_tree_path_free (path);
2445 drag_dest_path = NULL;
2447 if (tree_view->priv->cursor)
2448 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2451 _gtk_tree_view_find_node (tree_view, cursor_path,
2452 &cursor_tree, &cursor);
2454 if (tree_view->priv->drag_dest_row)
2455 drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
2458 _gtk_tree_view_find_node (tree_view, drag_dest_path,
2459 &drag_highlight_tree, &drag_highlight);
2461 gdk_drawable_get_size (tree_view->priv->bin_window,
2462 &bin_window_width, NULL);
2464 for (last_column = g_list_last (tree_view->priv->columns);
2466 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2467 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2468 last_column = last_column->prev)
2471 /* Actually process the expose event. To do this, we want to
2472 * start at the first node of the event, and walk the tree in
2473 * order, drawing each successive node.
2480 max_height = BACKGROUND_HEIGHT (node);
2482 x_offset = -event->area.x;
2484 highlight_x = 0; /* should match x coord of first cell */
2486 background_area.y = y_offset + event->area.y;
2487 background_area.height = max_height;
2490 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
2491 flags |= GTK_CELL_RENDERER_PRELIT;
2493 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
2494 flags |= GTK_CELL_RENDERER_SELECTED;
2496 parity = _gtk_rbtree_node_find_parity (tree, node);
2498 for (list = tree_view->priv->columns; list; list = list->next)
2500 GtkTreeViewColumn *column = list->data;
2501 const gchar *detail = NULL;
2503 if (!column->visible)
2506 if (cell_offset > event->area.x + event->area.width ||
2507 cell_offset + column->displayed_width < event->area.x)
2509 cell_offset += column->displayed_width;
2513 if (column->show_sort_indicator)
2514 flags |= GTK_CELL_RENDERER_SORTED;
2516 flags &= ~GTK_CELL_RENDERER_SORTED;
2518 gtk_tree_view_column_cell_set_cell_data (column,
2519 tree_view->priv->model,
2522 background_area.x = cell_offset;
2523 background_area.width = column->displayed_width;
2525 cell_area = background_area;
2526 cell_area.y += vertical_separator / 2;
2527 cell_area.height -= vertical_separator;
2529 /* Select the detail for drawing the cell. relevant
2530 * factors are parity, sortedness, and whether to
2534 /* FIXME when we have style properties, clean this up.
2537 if (tree_view->priv->has_rules)
2539 if (flags & GTK_CELL_RENDERER_SORTED)
2542 detail = "cell_odd_ruled_sorted";
2544 detail = "cell_even_ruled_sorted";
2549 detail = "cell_odd_ruled";
2551 detail = "cell_even_ruled";
2556 if (flags & GTK_CELL_RENDERER_SORTED)
2559 detail = "cell_odd_sorted";
2561 detail = "cell_even_sorted";
2566 detail = "cell_odd";
2568 detail = "cell_even";
2574 /* Draw background */
2575 gtk_paint_flat_box (widget->style,
2577 (flags & GTK_CELL_RENDERER_SELECTED) ?
2578 GTK_STATE_SELECTED : GTK_STATE_NORMAL,
2585 background_area.width,
2586 background_area.height);
2588 if (gtk_tree_view_is_expander_column (tree_view, column) &&
2589 TREE_VIEW_DRAW_EXPANDERS(tree_view))
2591 cell_area.x += depth*tree_view->priv->tab_offset;
2592 cell_area.width -= depth*tree_view->priv->tab_offset;
2594 /* If we have an expander column, the highlight underline
2595 * starts with that column, so that it indicates which
2596 * level of the tree we're dropping at.
2598 highlight_x = cell_area.x;
2600 gtk_tree_view_column_cell_render (column,
2606 if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
2609 gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
2610 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2618 gtk_tree_view_column_cell_render (column,
2625 cell_offset += column->displayed_width;
2628 if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
2629 gtk_tree_view_draw_focus (widget);
2631 if (node == drag_highlight)
2633 /* Draw indicator for the drop
2635 gint highlight_y = -1;
2636 GtkRBTree *tree = NULL;
2637 GtkRBNode *node = NULL;
2640 switch (tree_view->priv->drag_dest_pos)
2642 case GTK_TREE_VIEW_DROP_BEFORE:
2643 highlight_y = background_area.y - vertical_separator/2;
2646 case GTK_TREE_VIEW_DROP_AFTER:
2647 highlight_y = background_area.y + background_area.height + vertical_separator/2;
2650 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2651 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2652 _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
2656 gdk_drawable_get_size (tree_view->priv->bin_window,
2658 gtk_paint_focus (widget->style,
2659 tree_view->priv->bin_window,
2663 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
2664 width - 1, BACKGROUND_HEIGHT (node) - 1);
2669 if (highlight_y >= 0)
2671 gdk_draw_line (event->window,
2672 widget->style->black_gc,
2675 bin_window_width - highlight_x,
2680 y_offset += max_height;
2683 GtkTreeIter parent = iter;
2686 tree = node->children;
2689 g_assert (node != tree->nil);
2691 while (node->left != tree->nil)
2693 has_child = gtk_tree_model_iter_children (tree_view->priv->model,
2699 TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
2703 gboolean done = FALSE;
2706 node = _gtk_rbtree_next (tree, node);
2709 gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
2713 TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
2717 GtkTreeIter parent_iter = iter;
2718 gboolean has_parent;
2720 node = tree->parent_node;
2721 tree = tree->parent_tree;
2723 /* we've run out of tree. It's okay to return though, as
2724 * we'd only break out of the while loop below. */
2726 has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
2732 TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
2738 while (y_offset < event->area.height);
2741 gtk_tree_path_free (cursor_path);
2744 gtk_tree_path_free (drag_dest_path);
2750 gtk_tree_view_expose (GtkWidget *widget,
2751 GdkEventExpose *event)
2753 GtkTreeView *tree_view;
2755 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2757 tree_view = GTK_TREE_VIEW (widget);
2759 if (event->window == tree_view->priv->bin_window)
2760 return gtk_tree_view_bin_expose (widget, event);
2766 gtk_tree_view_key_press (GtkWidget *widget,
2769 GtkTreeView *tree_view = (GtkTreeView *) widget;
2771 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2773 if (event->keyval == GDK_Escape)
2775 tree_view->priv->cur_reorder = NULL;
2776 gtk_tree_view_button_release_drag_column (widget, NULL);
2780 return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
2783 /* FIXME Is this function necessary? Can I get an enter_notify event
2784 * w/o either an expose event or a mouse motion event?
2787 gtk_tree_view_enter_notify (GtkWidget *widget,
2788 GdkEventCrossing *event)
2790 GtkTreeView *tree_view;
2795 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2797 tree_view = GTK_TREE_VIEW (widget);
2799 /* Sanity check it */
2800 if (event->window != tree_view->priv->bin_window)
2803 if (tree_view->priv->tree == NULL)
2806 if ((tree_view->priv->button_pressed_node != NULL) &&
2807 (tree_view->priv->button_pressed_node != node))
2810 /* find the node internally */
2811 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2813 _gtk_rbtree_find_offset (tree_view->priv->tree,
2814 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2821 do_prelight (tree_view, tree, node, event->x, new_y);
2823 if (tree_view->priv->prelight_node)
2824 gtk_tree_view_queue_draw_node (tree_view,
2825 tree_view->priv->prelight_tree,
2826 tree_view->priv->prelight_node,
2833 gtk_tree_view_leave_notify (GtkWidget *widget,
2834 GdkEventCrossing *event)
2836 GtkTreeView *tree_view;
2838 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2840 tree_view = GTK_TREE_VIEW (widget);
2842 if (tree_view->priv->prelight_node)
2843 gtk_tree_view_queue_draw_node (tree_view,
2844 tree_view->priv->prelight_tree,
2845 tree_view->priv->prelight_node,
2848 ensure_unprelighted (tree_view);
2855 gtk_tree_view_focus_in (GtkWidget *widget,
2856 GdkEventFocus *event)
2858 GtkTreeView *tree_view;
2860 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2861 g_return_val_if_fail (event != NULL, FALSE);
2863 tree_view = GTK_TREE_VIEW (widget);
2865 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2867 gtk_widget_queue_draw (widget);
2874 gtk_tree_view_focus_out (GtkWidget *widget,
2875 GdkEventFocus *event)
2877 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2878 g_return_val_if_fail (event != NULL, FALSE);
2880 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2882 gtk_widget_queue_draw (widget);
2883 GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE;
2884 GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE;
2892 set_source_row (GdkDragContext *context,
2893 GtkTreeModel *model,
2894 GtkTreePath *source_row)
2896 g_object_set_data_full (G_OBJECT (context),
2897 "gtk-tree-view-source-row",
2898 source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
2899 (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
2903 get_source_row (GdkDragContext *context)
2905 GtkTreeRowReference *ref =
2906 g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
2909 return gtk_tree_row_reference_get_path (ref);
2916 set_dest_row (GdkDragContext *context,
2917 GtkTreeModel *model,
2918 GtkTreePath *dest_row)
2920 g_object_set_data_full (G_OBJECT (context),
2921 "gtk-tree-view-dest-row",
2922 dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
2923 (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
2927 get_dest_row (GdkDragContext *context)
2929 GtkTreeRowReference *ref =
2930 g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
2933 return gtk_tree_row_reference_get_path (ref);
2938 /* Get/set whether drag_motion requested the drag data and
2939 * drag_data_received should thus not actually insert the data,
2940 * since the data doesn't result from a drop.
2943 set_status_pending (GdkDragContext *context,
2944 GdkDragAction suggested_action)
2946 g_object_set_data (G_OBJECT (context),
2947 "gtk-tree-view-status-pending",
2948 GINT_TO_POINTER (suggested_action));
2951 static GdkDragAction
2952 get_status_pending (GdkDragContext *context)
2954 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
2955 "gtk-tree-view-status-pending"));
2958 static TreeViewDragInfo*
2959 get_info (GtkTreeView *tree_view)
2961 return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
2965 clear_source_info (TreeViewDragInfo *di)
2967 if (di->source_target_list)
2968 gtk_target_list_unref (di->source_target_list);
2970 if (di->row_draggable_closure)
2971 g_closure_unref (di->row_draggable_closure);
2973 di->source_target_list = NULL;
2974 di->row_draggable_closure = NULL;
2978 clear_dest_info (TreeViewDragInfo *di)
2980 if (di->location_droppable_closure)
2981 g_closure_unref (di->location_droppable_closure);
2983 if (di->dest_target_list)
2984 gtk_target_list_unref (di->dest_target_list);
2986 di->location_droppable_closure = NULL;
2987 di->dest_target_list = NULL;
2991 destroy_info (TreeViewDragInfo *di)
2993 clear_source_info (di);
2994 clear_dest_info (di);
2998 static TreeViewDragInfo*
2999 ensure_info (GtkTreeView *tree_view)
3001 TreeViewDragInfo *di;
3003 di = get_info (tree_view);
3007 di = g_new0 (TreeViewDragInfo, 1);
3009 g_object_set_data_full (G_OBJECT (tree_view),
3010 "gtk-tree-view-drag-info",
3012 (GDestroyNotify) destroy_info);
3019 remove_info (GtkTreeView *tree_view)
3021 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 tree_view = GTK_TREE_VIEW (data);
3036 gdk_window_get_pointer (tree_view->priv->bin_window,
3039 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3041 /* See if we are near the edge. */
3042 if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
3043 (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
3044 (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
3045 (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
3047 gtk_tree_view_get_path_at_pos (tree_view,
3048 tree_view->priv->bin_window,
3057 gtk_tree_view_scroll_to_cell (tree_view,
3062 gtk_tree_path_free (path);
3071 remove_scroll_timeout (GtkTreeView *tree_view)
3073 if (tree_view->priv->scroll_timeout != 0)
3075 gtk_timeout_remove (tree_view->priv->scroll_timeout);
3076 tree_view->priv->scroll_timeout = 0;
3080 check_model_dnd (GtkTreeModel *model,
3081 GType required_iface,
3082 const gchar *signal)
3084 if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
3086 g_warning ("You must override the default '%s' handler "
3087 "on GtkTreeView when using models that don't support "
3088 "the %s interface and enabling drag-and-drop. The simplest way to do this "
3089 "is to connect to '%s' and call "
3090 "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
3091 "the default handler from running. Look at the source code "
3092 "for the default handler in gtktreeview.c to get an idea what "
3093 "your handler should do. (gtktreeview.c is in the GTK source "
3094 "code.) If you're using GTK from a language other than C, "
3095 "there may be a more natural way to override default handlers, e.g. via derivation.",
3096 signal, g_type_name (required_iface), signal);
3104 remove_open_timeout (GtkTreeView *tree_view)
3106 if (tree_view->priv->open_dest_timeout != 0)
3108 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
3109 tree_view->priv->open_dest_timeout = 0;
3115 open_row_timeout (gpointer data)
3117 GtkTreeView *tree_view = data;
3118 GtkTreePath *dest_path = NULL;
3119 GtkTreeViewDropPosition pos;
3121 gtk_tree_view_get_drag_dest_row (tree_view,
3126 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3127 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3129 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
3130 tree_view->priv->open_dest_timeout = 0;
3132 gtk_tree_path_free (dest_path);
3139 gtk_tree_path_free (dest_path);
3144 /* Returns TRUE if event should not be propagated to parent widgets */
3146 set_destination_row (GtkTreeView *tree_view,
3147 GdkDragContext *context,
3150 GdkDragAction *suggested_action,
3153 GtkTreePath *path = NULL;
3154 GtkTreeViewDropPosition pos;
3155 GtkTreeViewDropPosition old_pos;
3156 TreeViewDragInfo *di;
3158 GtkTreePath *old_dest_path = NULL;
3160 *suggested_action = 0;
3163 widget = GTK_WIDGET (tree_view);
3165 di = get_info (tree_view);
3169 /* someone unset us as a drag dest, note that if
3170 * we return FALSE drag_leave isn't called
3173 gtk_tree_view_set_drag_dest_row (tree_view,
3175 GTK_TREE_VIEW_DROP_BEFORE);
3177 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3178 remove_open_timeout (GTK_TREE_VIEW (widget));
3180 return FALSE; /* no longer a drop site */
3183 *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
3184 if (*target == GDK_NONE)
3189 if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
3194 /* can't drop here */
3195 remove_open_timeout (tree_view);
3197 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3199 GTK_TREE_VIEW_DROP_BEFORE);
3201 /* don't propagate to parent though */
3207 /* If we left the current row's "open" zone, unset the timeout for
3210 gtk_tree_view_get_drag_dest_row (tree_view,
3214 if (old_dest_path &&
3215 (gtk_tree_path_compare (path, old_dest_path) != 0 ||
3216 !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3217 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
3218 remove_open_timeout (tree_view);
3221 gtk_tree_path_free (old_dest_path);
3223 if (TRUE /* FIXME if the location droppable predicate */)
3225 GtkWidget *source_widget;
3227 *suggested_action = context->suggested_action;
3229 source_widget = gtk_drag_get_source_widget (context);
3231 if (source_widget == widget)
3233 /* Default to MOVE, unless the user has
3234 * pressed ctrl or alt to affect available actions
3236 if ((context->actions & GDK_ACTION_MOVE) != 0)
3237 *suggested_action = GDK_ACTION_MOVE;
3240 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3245 /* can't drop here */
3246 remove_open_timeout (tree_view);
3248 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3250 GTK_TREE_VIEW_DROP_BEFORE);
3256 get_logical_dest_row (GtkTreeView *tree_view)
3259 /* adjust path to point to the row the drop goes in front of */
3260 GtkTreePath *path = NULL;
3261 GtkTreeViewDropPosition pos;
3263 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3268 if (pos == GTK_TREE_VIEW_DROP_BEFORE)
3270 else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
3271 pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3273 /* get first child, drop before it */
3274 gtk_tree_path_append_index (path, 0);
3278 g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
3279 gtk_tree_path_next (path);
3286 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
3287 GdkEventMotion *event)
3289 GdkDragContext *context;
3290 TreeViewDragInfo *di;
3291 GtkTreePath *path = NULL;
3293 gint cell_x, cell_y;
3294 GtkTreeModel *model;
3296 di = get_info (tree_view);
3301 if (tree_view->priv->pressed_button < 0)
3304 if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
3305 tree_view->priv->press_start_x,
3306 tree_view->priv->press_start_y,
3307 event->x, event->y))
3310 model = gtk_tree_view_get_model (tree_view);
3315 button = tree_view->priv->pressed_button;
3316 tree_view->priv->pressed_button = -1;
3318 gtk_tree_view_get_path_at_pos (tree_view,
3319 tree_view->priv->bin_window,
3320 tree_view->priv->press_start_x,
3321 tree_view->priv->press_start_y,
3330 /* FIXME if the path doesn't match the row_draggable predicate,
3331 * return FALSE and free path
3334 /* FIXME Check whether we're a start button, if not return FALSE and
3338 context = gtk_drag_begin (GTK_WIDGET (tree_view),
3339 di->source_target_list,
3344 gtk_drag_set_icon_default (context);
3349 row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
3352 gtk_drag_set_icon_pixmap (context,
3353 gdk_drawable_get_colormap (row_pix),
3356 /* the + 1 is for the black border in the icon */
3357 tree_view->priv->press_start_x + 1,
3360 gdk_pixmap_unref (row_pix);
3363 set_source_row (context, model, path);
3364 gtk_tree_path_free (path);
3371 gtk_tree_view_drag_begin (GtkWidget *widget,
3372 GdkDragContext *context)
3378 gtk_tree_view_drag_end (GtkWidget *widget,
3379 GdkDragContext *context)
3384 /* Default signal implementations for the drag signals */
3386 gtk_tree_view_drag_data_get (GtkWidget *widget,
3387 GdkDragContext *context,
3388 GtkSelectionData *selection_data,
3392 GtkTreeView *tree_view;
3393 GtkTreeModel *model;
3394 TreeViewDragInfo *di;
3395 GtkTreePath *source_row;
3397 tree_view = GTK_TREE_VIEW (widget);
3399 model = gtk_tree_view_get_model (tree_view);
3404 di = get_info (GTK_TREE_VIEW (widget));
3409 source_row = get_source_row (context);
3411 if (source_row == NULL)
3414 /* We can implement the GTK_TREE_MODEL_ROW target generically for
3415 * any model; for DragSource models there are some other targets
3419 if (GTK_IS_TREE_DRAG_SOURCE (model) &&
3420 gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
3425 /* If drag_data_get does nothing, try providing row data. */
3426 if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3428 gtk_selection_data_set_tree_row (selection_data,
3434 gtk_tree_path_free (source_row);
3439 gtk_tree_view_drag_data_delete (GtkWidget *widget,
3440 GdkDragContext *context)
3442 TreeViewDragInfo *di;
3443 GtkTreeModel *model;
3444 GtkTreeView *tree_view;
3445 GtkTreePath *source_row;
3447 tree_view = GTK_TREE_VIEW (widget);
3448 model = gtk_tree_view_get_model (tree_view);
3450 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
3453 di = get_info (tree_view);
3458 source_row = get_source_row (context);
3460 if (source_row == NULL)
3463 gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
3466 gtk_tree_path_free (source_row);
3468 set_source_row (context, NULL, NULL);
3472 gtk_tree_view_drag_leave (GtkWidget *widget,
3473 GdkDragContext *context,
3476 TreeViewDragInfo *di;
3478 di = get_info (GTK_TREE_VIEW (widget));
3480 /* unset any highlight row */
3481 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3483 GTK_TREE_VIEW_DROP_BEFORE);
3485 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3486 remove_open_timeout (GTK_TREE_VIEW (widget));
3491 gtk_tree_view_drag_motion (GtkWidget *widget,
3492 GdkDragContext *context,
3497 GtkTreePath *path = NULL;
3498 GtkTreeViewDropPosition pos;
3499 GtkTreeView *tree_view;
3500 GdkDragAction suggested_action = 0;
3503 tree_view = GTK_TREE_VIEW (widget);
3505 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3508 // gtk_tree_view_ensure_scroll_timeout (tree_view);
3510 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3514 /* Can't drop here. */
3515 gdk_drag_status (context, 0, time);
3519 if (tree_view->priv->open_dest_timeout == 0 &&
3520 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3521 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3523 tree_view->priv->open_dest_timeout =
3524 gtk_timeout_add (500, open_row_timeout, tree_view);
3527 if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3529 /* Request data so we can use the source row when
3530 * determining whether to accept the drop
3532 set_status_pending (context, suggested_action);
3533 gtk_drag_get_data (widget, context, target, time);
3537 set_status_pending (context, 0);
3538 gdk_drag_status (context, suggested_action, time);
3543 gtk_tree_path_free (path);
3550 gtk_tree_view_drag_drop (GtkWidget *widget,
3551 GdkDragContext *context,
3556 GtkTreeView *tree_view;
3558 GdkDragAction suggested_action = 0;
3559 GdkAtom target = GDK_NONE;
3560 TreeViewDragInfo *di;
3561 GtkTreeModel *model;
3563 tree_view = GTK_TREE_VIEW (widget);
3565 model = gtk_tree_view_get_model (tree_view);
3567 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3568 remove_open_timeout (GTK_TREE_VIEW (widget));
3570 di = get_info (tree_view);
3575 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
3578 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3581 path = get_logical_dest_row (tree_view);
3583 if (target != GDK_NONE && path != NULL)
3585 /* in case a motion had requested drag data, change things so we
3586 * treat drag data receives as a drop.
3588 set_status_pending (context, 0);
3590 set_dest_row (context, model, path);
3594 gtk_tree_path_free (path);
3596 /* Unset this thing */
3597 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3599 GTK_TREE_VIEW_DROP_BEFORE);
3601 if (target != GDK_NONE)
3603 gtk_drag_get_data (widget, context, target, time);
3611 gtk_tree_view_drag_data_received (GtkWidget *widget,
3612 GdkDragContext *context,
3615 GtkSelectionData *selection_data,
3620 TreeViewDragInfo *di;
3621 gboolean accepted = FALSE;
3622 GtkTreeModel *model;
3623 GtkTreeView *tree_view;
3624 GtkTreePath *dest_row;
3625 GdkDragAction suggested_action;
3627 tree_view = GTK_TREE_VIEW (widget);
3629 model = gtk_tree_view_get_model (tree_view);
3631 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
3634 di = get_info (tree_view);
3639 suggested_action = get_status_pending (context);
3641 if (suggested_action)
3643 /* We are getting this data due to a request in drag_motion,
3644 * rather than due to a request in drag_drop, so we are just
3645 * supposed to call drag_status, not actually paste in the
3648 path = get_logical_dest_row (tree_view);
3651 suggested_action = 0;
3653 if (suggested_action)
3655 GtkTreeModel *src_model = NULL;
3656 GtkTreePath *src_path = NULL;
3658 if (!gtk_selection_data_get_tree_row (selection_data,
3661 suggested_action = 0;
3663 if (suggested_action)
3665 if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
3669 suggested_action = 0;
3671 gtk_tree_path_free (src_path);
3675 gdk_drag_status (context, suggested_action, time);
3678 gtk_tree_path_free (path);
3680 /* If you can't drop, remove user drop indicator until the next motion */
3681 if (suggested_action == 0)
3682 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3684 GTK_TREE_VIEW_DROP_BEFORE);
3689 dest_row = get_dest_row (context);
3691 if (dest_row == NULL)
3694 if (selection_data->length >= 0)
3696 if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
3702 gtk_drag_finish (context,
3704 (context->action == GDK_ACTION_MOVE),
3707 gtk_tree_path_free (dest_row);
3710 set_dest_row (context, NULL, NULL);
3715 /* GtkContainer Methods
3720 gtk_tree_view_remove (GtkContainer *container,
3723 GtkTreeView *tree_view;
3724 GtkTreeViewChild *child = NULL;
3727 g_return_if_fail (GTK_IS_TREE_VIEW (container));
3729 tree_view = GTK_TREE_VIEW (container);
3731 tmp_list = tree_view->priv->children;
3734 child = tmp_list->data;
3735 if (child->widget == widget)
3737 gtk_widget_unparent (widget);
3739 tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
3740 g_list_free_1 (tmp_list);
3745 tmp_list = tmp_list->next;
3748 tmp_list = tree_view->priv->columns;
3752 GtkTreeViewColumn *column;
3753 column = tmp_list->data;
3754 if (column->button == widget)
3756 gtk_widget_unparent (widget);
3759 tmp_list = tmp_list->next;
3765 gtk_tree_view_forall (GtkContainer *container,
3766 gboolean include_internals,
3767 GtkCallback callback,
3768 gpointer callback_data)
3770 GtkTreeView *tree_view;
3771 GtkTreeViewChild *child = NULL;
3772 GtkTreeViewColumn *column;
3775 g_return_if_fail (GTK_IS_TREE_VIEW (container));
3776 g_return_if_fail (callback != NULL);
3778 tree_view = GTK_TREE_VIEW (container);
3780 tmp_list = tree_view->priv->children;
3783 child = tmp_list->data;
3784 tmp_list = tmp_list->next;
3786 (* callback) (child->widget, callback_data);
3788 if (include_internals == FALSE)
3791 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3793 column = tmp_list->data;
3796 (* callback) (column->button, callback_data);
3800 /* Returns TRUE if the focus is within the headers, after the focus operation is
3804 gtk_tree_view_header_focus (GtkTreeView *tree_view,
3805 GtkDirectionType dir)
3807 GtkWidget *focus_child;
3808 GtkContainer *container;
3810 GList *last_column, *first_column;
3813 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
3816 focus_child = GTK_CONTAINER (tree_view)->focus_child;
3817 container = GTK_CONTAINER (tree_view);
3819 last_column = g_list_last (tree_view->priv->columns);
3822 if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
3823 GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
3825 last_column = last_column->prev;
3828 /* No headers are visible, or are focusable. We can't focus in or out.
3830 if (last_column == NULL)
3833 first_column = tree_view->priv->columns;
3834 while (first_column)
3836 if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
3837 GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
3839 first_column = first_column->next;
3844 case GTK_DIR_TAB_BACKWARD:
3845 case GTK_DIR_TAB_FORWARD:
3848 if (focus_child == NULL)
3850 if (tree_view->priv->focus_column != NULL)
3851 focus_child = tree_view->priv->focus_column->button;
3853 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3854 gtk_widget_grab_focus (focus_child);
3861 if (focus_child == NULL)
3863 if (tree_view->priv->focus_column != NULL)
3864 focus_child = tree_view->priv->focus_column->button;
3865 else if (dir == GTK_DIR_LEFT)
3866 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3868 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3869 gtk_widget_grab_focus (focus_child);
3873 if (gtk_widget_child_focus (focus_child, dir))
3875 /* The focus moves inside the button. */
3876 /* This is probably a great example of bad UI */
3880 /* We need to move the focus among the row of buttons. */
3881 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3882 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3885 if (tmp_list == first_column && dir == GTK_DIR_LEFT)
3887 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3888 gtk_widget_grab_focus (focus_child);
3891 else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
3893 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3894 gtk_widget_grab_focus (focus_child);
3900 GtkTreeViewColumn *column;
3902 if (dir == GTK_DIR_RIGHT)
3903 tmp_list = tmp_list->next;
3905 tmp_list = tmp_list->prev;
3907 if (tmp_list == NULL)
3909 g_warning ("Internal button not found");
3912 column = tmp_list->data;
3913 if (column->button &&
3915 GTK_WIDGET_CAN_FOCUS (column->button))
3917 focus_child = column->button;
3918 gtk_widget_grab_focus (column->button);
3924 g_assert_not_reached ();
3928 /* if focus child is non-null, we assume it's been set to the current focus child
3932 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3933 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3936 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3938 /* If the following isn't true, then the view is smaller then the scrollpane.
3940 if ((focus_child->allocation.x + focus_child->allocation.width) <=
3941 (tree_view->priv->hadjustment->upper))
3943 /* Scroll to the button, if needed */
3944 if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
3945 (focus_child->allocation.x + focus_child->allocation.width))
3946 gtk_adjustment_set_value (tree_view->priv->hadjustment,
3947 focus_child->allocation.x + focus_child->allocation.width -
3948 tree_view->priv->hadjustment->page_size);
3949 else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
3950 gtk_adjustment_set_value (tree_view->priv->hadjustment,
3951 focus_child->allocation.x);
3955 return (focus_child != NULL);
3958 /* We make the assumption that if container->focus_child != NULL, the focus must
3959 * be in the header. For now, this is accurate. It may not be in the future.
3962 /* The sordid relationship between focus_column and scroll_column:
3964 * The focus_column represents the column that currently has keyboard focus, and
3965 * is used when navigating columns by keyboard. scroll_column is used for
3966 * handling scrolling by keyboard, such that in cases.
3969 gtk_tree_view_focus (GtkWidget *widget,
3970 GtkDirectionType direction)
3972 GtkTreeView *tree_view;
3973 GtkWidget *focus_child;
3974 GtkContainer *container;
3976 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3977 g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
3979 container = GTK_CONTAINER (widget);
3980 tree_view = GTK_TREE_VIEW (widget);
3982 if (!GTK_WIDGET_IS_SENSITIVE (container))
3985 focus_child = container->focus_child;
3987 /* Case 1. Headers currently have focus. */
3994 gtk_tree_view_header_focus (tree_view, direction);
3996 case GTK_DIR_TAB_BACKWARD:
3999 case GTK_DIR_TAB_FORWARD:
4001 if (tree_view->priv->tree == NULL)
4003 gtk_tree_view_focus_to_cursor (tree_view);
4008 /* Case 2. We don't have focus at all. */
4009 if (!GTK_WIDGET_HAS_FOCUS (container))
4011 if (tree_view->priv->tree == NULL &&
4012 (direction == GTK_DIR_TAB_BACKWARD ||
4013 direction == GTK_DIR_UP))
4014 return gtk_tree_view_header_focus (tree_view, direction);
4015 if (((direction == GTK_DIR_TAB_FORWARD) ||
4016 (direction == GTK_DIR_RIGHT) ||
4017 (direction == GTK_DIR_DOWN) ||
4018 (direction == GTK_DIR_LEFT)) &&
4019 gtk_tree_view_header_focus (tree_view, direction))
4022 if (tree_view->priv->tree == NULL)
4024 gtk_tree_view_focus_to_cursor (tree_view);
4028 /* Case 3. We have focus already. */
4029 if (tree_view->priv->tree == NULL)
4030 return gtk_tree_view_header_focus (tree_view, direction);
4032 if (direction == GTK_DIR_TAB_BACKWARD)
4033 return (gtk_tree_view_header_focus (tree_view, direction));
4034 else if (direction == GTK_DIR_TAB_FORWARD)
4037 /* Other directions caught by the keybindings */
4038 gtk_tree_view_focus_to_cursor (tree_view);
4044 gtk_tree_view_set_focus_child (GtkContainer *container,
4047 GtkTreeView *tree_view = GTK_TREE_VIEW (container);
4050 for (list = tree_view->priv->columns; list; list = list->next)
4052 if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
4054 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
4059 (* parent_class->set_focus_child) (container, child);
4063 gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
4064 GtkAdjustment *hadj,
4065 GtkAdjustment *vadj)
4067 gboolean need_adjust = FALSE;
4069 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4072 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4074 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4076 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4078 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4080 if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4082 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4083 gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4086 if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4088 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4089 gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4092 if (tree_view->priv->hadjustment != hadj)
4094 tree_view->priv->hadjustment = hadj;
4095 gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4096 gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4098 gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4099 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4104 if (tree_view->priv->vadjustment != vadj)
4106 tree_view->priv->vadjustment = vadj;
4107 gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4108 gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4110 gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4111 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4117 gtk_tree_view_adjustment_changed (NULL, tree_view);
4121 gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view)
4123 tree_view->priv->in_extended_selection = TRUE;
4127 gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view)
4129 tree_view->priv->in_extended_selection = FALSE;
4133 gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view)
4135 tree_view->priv->in_free_motion = TRUE;
4139 gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view)
4141 tree_view->priv->in_free_motion = FALSE;
4145 gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
4146 GtkMovementStep step,
4149 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4150 g_return_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
4151 step == GTK_MOVEMENT_VISUAL_POSITIONS ||
4152 step == GTK_MOVEMENT_DISPLAY_LINES ||
4153 step == GTK_MOVEMENT_PAGES ||
4154 step == GTK_MOVEMENT_BUFFER_ENDS);
4156 if (tree_view->priv->tree == NULL)
4159 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
4160 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
4164 /* currently we make no distinction. When we go bi-di, we need to */
4165 case GTK_MOVEMENT_LOGICAL_POSITIONS:
4166 case GTK_MOVEMENT_VISUAL_POSITIONS:
4167 gtk_tree_view_move_cursor_left_right (tree_view, count);
4169 case GTK_MOVEMENT_DISPLAY_LINES:
4170 gtk_tree_view_move_cursor_up_down (tree_view, count);
4172 case GTK_MOVEMENT_PAGES:
4173 gtk_tree_view_move_cursor_page_up_down (tree_view, count);
4175 case GTK_MOVEMENT_BUFFER_ENDS:
4176 gtk_tree_view_move_cursor_start_end (tree_view, count);
4179 g_assert_not_reached ();
4183 /* TreeModel Callbacks
4187 gtk_tree_view_range_changed (GtkTreeModel *model,
4190 GtkTreePath *end_path,
4191 GtkTreeIter *end_iter,
4194 GtkTreeView *tree_view = (GtkTreeView *)data;
4198 gboolean dirty_marked;
4199 gboolean free_path = FALSE;
4200 gint vertical_separator;
4203 g_return_if_fail (path != NULL || iter != NULL);
4205 gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
4209 path = gtk_tree_model_get_path (model, iter);
4212 else if (iter == NULL)
4213 gtk_tree_model_get_iter (model, iter, path);
4215 if (_gtk_tree_view_find_node (tree_view,
4219 /* We aren't actually showing the node */
4225 dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
4227 gtk_tree_path_get_depth (path),
4230 if (GTK_RBNODE_GET_HEIGHT (node) != height + vertical_separator)
4232 _gtk_rbtree_node_set_height (tree, node, height + vertical_separator);
4233 gtk_widget_queue_resize (GTK_WIDGET (data));
4237 gtk_widget_queue_resize (GTK_WIDGET (data));
4239 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
4243 gtk_tree_path_free (path);
4247 gtk_tree_view_inserted (GtkTreeModel *model,
4252 GtkTreeView *tree_view = (GtkTreeView *) data;
4254 GtkRBTree *tmptree, *tree;
4255 GtkRBNode *tmpnode = NULL;
4259 gboolean free_path = FALSE;
4261 if (tree_view->priv->tree == NULL)
4262 tree_view->priv->tree = _gtk_rbtree_new ();
4264 tmptree = tree = tree_view->priv->tree;
4265 g_return_if_fail (path != NULL || iter != NULL);
4269 path = gtk_tree_model_get_path (model, iter);
4272 else if (iter == NULL)
4273 gtk_tree_model_get_iter (model, iter, path);
4275 /* Update all row-references */
4276 gtk_tree_row_reference_inserted (G_OBJECT (data), path);
4278 depth = gtk_tree_path_get_depth (path);
4279 indices = gtk_tree_path_get_indices (path);
4281 /* First, find the parent tree */
4282 while (i < depth - 1)
4284 if (tmptree == NULL)
4286 /* We aren't showing the node */
4290 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
4291 if (tmpnode == NULL)
4293 g_warning ("A node was inserted with a parent that's not in the tree.\n" \
4294 "This possibly means that a GtkTreeModel inserted a child node\n" \
4295 "before the parent was inserted.");
4298 else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
4300 /* FIXME enforce correct behavior on model, probably */
4301 /* In theory, the model should have emitted has_child_toggled here. We
4302 * try to catch it anyway, just to be safe, in case the model hasn't.
4304 GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
4307 gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
4308 gtk_tree_path_free (tmppath);
4312 tmptree = tmpnode->children;
4321 gtk_tree_model_ref_node (tree_view->priv->model, iter);
4322 max_height = gtk_tree_view_insert_iter_height (tree_view,
4326 if (indices[depth - 1] == 0)
4328 tmpnode = _gtk_rbtree_find_count (tree, 1);
4329 _gtk_rbtree_insert_before (tree, tmpnode, max_height);
4333 tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
4334 _gtk_rbtree_insert_after (tree, tmpnode, max_height);
4337 _gtk_tree_view_update_size (tree_view);
4341 gtk_tree_path_free (path);
4345 gtk_tree_view_has_child_toggled (GtkTreeModel *model,
4350 GtkTreeView *tree_view = (GtkTreeView *)data;
4351 GtkTreeIter real_iter;
4355 gboolean free_path = FALSE;
4357 g_return_if_fail (path != NULL || iter != NULL);
4364 path = gtk_tree_model_get_path (model, iter);
4367 else if (iter == NULL)
4368 gtk_tree_model_get_iter (model, &real_iter, path);
4370 if (_gtk_tree_view_find_node (tree_view,
4374 /* We aren't actually showing the node */
4380 has_child = gtk_tree_model_iter_has_child (model, &real_iter);
4383 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
4387 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
4389 GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
4391 if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
4393 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4394 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
4398 for (list = tree_view->priv->columns; list; list = list->next)
4399 if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
4401 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
4405 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4409 /* FIXME: Just redraw the node */
4410 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4415 gtk_tree_path_free (path);
4419 count_children_helper (GtkRBTree *tree,
4424 _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
4425 (*((gint *)data))++;
4429 gtk_tree_view_deleted (GtkTreeModel *model,
4433 GtkTreeView *tree_view = (GtkTreeView *)data;
4438 g_return_if_fail (path != NULL);
4440 if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
4446 gtk_tree_row_reference_deleted (G_OBJECT (data), path);
4448 /* Change the selection */
4449 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4450 g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
4452 for (list = tree_view->priv->columns; list; list = list->next)
4453 if (((GtkTreeViewColumn *)list->data)->visible &&
4454 ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4455 ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
4457 /* Ensure we don't have a dangling pointer to a dead node */
4458 ensure_unprelighted (tree_view);
4460 if (tree_view->priv->destroy_count_func)
4462 gint child_count = 0;
4464 _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
4465 (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
4468 if (tree->root->count == 1)
4470 if (tree_view->priv->tree == tree)
4471 tree_view->priv->tree = NULL;
4473 _gtk_rbtree_remove (tree);
4477 _gtk_rbtree_remove_node (tree, node);
4480 _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
4485 gtk_tree_view_reordered (GtkTreeModel *model,
4486 GtkTreePath *parent,
4491 GtkTreeView *tree_view = GTK_TREE_VIEW (data);
4496 len = gtk_tree_model_iter_n_children (model, iter);
4501 gtk_tree_row_reference_reordered (G_OBJECT (data),
4506 if (_gtk_tree_view_find_node (tree_view,
4512 /* We need to special case the parent path */
4514 tree = tree_view->priv->tree;
4516 tree = node->children;
4521 /* FIXME: we need to unprelight our tree, if it's prelit. */
4522 _gtk_rbtree_reorder (tree, new_order, len);
4524 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4528 /* Internal tree functions
4533 gtk_tree_view_get_background_xrange (GtkTreeView *tree_view,
4535 GtkTreeViewColumn *column,
4539 GtkTreeViewColumn *tmp_column = NULL;
4550 for (list = tree_view->priv->columns; list; list = list->next)
4552 tmp_column = list->data;
4554 if (tmp_column == column)
4557 if (tmp_column->visible)
4558 total_width += tmp_column->width;
4561 if (tmp_column != column)
4563 g_warning (G_STRLOC": passed-in column isn't in the tree");
4572 if (column->visible)
4573 *x2 = total_width + column->width;
4575 *x2 = total_width; /* width of 0 */
4580 gtk_tree_view_get_cell_xrange (GtkTreeView *tree_view,
4582 GtkTreeViewColumn *column,
4586 GtkTreeViewColumn *tmp_column = NULL;
4597 for (list = tree_view->priv->columns; list; list = list->next)
4599 tmp_column = list->data;
4601 if (tmp_column == column)
4604 if (tmp_column->visible)
4605 total_width += tmp_column->width;
4608 if (tmp_column != column)
4610 g_warning (G_STRLOC": passed-in column isn't in the tree");
4614 /* Remember we're getting the cell range, i.e. the cell_area passed
4615 * to the cell renderer.
4618 if (gtk_tree_view_is_expander_column (tree_view, column))
4619 total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
4626 if (column->visible)
4627 *x2 = total_width + column->displayed_width;
4629 *x2 = total_width; /* width of 0 */
4634 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
4640 GtkTreeViewColumn *tmp_column = NULL;
4644 for (list = tree_view->priv->columns; list; list = list->next)
4646 tmp_column = list->data;
4648 if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
4650 x_offset = total_width;
4654 if (tmp_column->visible)
4655 total_width += tmp_column->width;
4661 if (tmp_column && tmp_column->visible)
4663 /* +1 because x2 isn't included in the range. */
4665 *x2 = x_offset + tree_view->priv->tab_offset + 1;
4669 /* return an empty range, the expander column is hidden */
4676 gtk_tree_view_setup_model (GtkTreeView *tree_view)
4681 tree_view->priv->tree = NULL;
4683 g_signal_connect (tree_view->priv->model,
4685 (GCallback) gtk_tree_view_range_changed,
4687 g_signal_connect (tree_view->priv->model,
4689 (GCallback) gtk_tree_view_inserted,
4691 g_signal_connect (tree_view->priv->model,
4692 "has_child_toggled",
4693 (GCallback) gtk_tree_view_has_child_toggled,
4695 g_signal_connect (tree_view->priv->model,
4697 (GCallback) gtk_tree_view_deleted,
4699 g_signal_connect (tree_view->priv->model,
4701 (GCallback) gtk_tree_view_reordered,
4704 if (tree_view->priv->columns == NULL)
4707 path = gtk_tree_path_new_root ();
4709 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
4711 tree_view->priv->tree = _gtk_rbtree_new ();
4712 gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
4715 gtk_tree_path_free (path);
4717 /* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
4719 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
4723 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
4728 GtkTreeViewColumn *column;
4730 gint max_height = 0;
4731 gint vertical_separator;
4733 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4734 /* do stuff with node */
4735 for (list = tree_view->priv->columns; list; list = list->next)
4737 gint height = 0, width = 0;
4738 column = list->data;
4740 if (!column->visible)
4743 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4746 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4748 gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4749 max_height = MAX (max_height, vertical_separator + height);
4751 if (gtk_tree_view_is_expander_column (tree_view, column) &&
4752 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4753 _gtk_tree_view_column_set_width (column,
4754 MAX (column->width, depth * tree_view->priv->tab_offset + width));
4756 _gtk_tree_view_column_set_width (column,
4757 MAX (column->width, width));
4763 gtk_tree_view_build_tree (GtkTreeView *tree_view,
4768 gboolean calc_bounds)
4770 GtkRBNode *temp = NULL;
4777 max_height = gtk_tree_view_insert_iter_height (tree_view,
4782 gtk_tree_model_ref_node (tree_view->priv->model, iter);
4783 temp = _gtk_rbtree_insert_after (tree, temp, max_height);
4788 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4790 temp->children = _gtk_rbtree_new ();
4791 temp->children->parent_tree = tree;
4792 temp->children->parent_node = temp;
4793 gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
4796 if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
4798 if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
4799 temp->flags ^= GTK_RBNODE_IS_PARENT;
4800 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4803 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4807 gtk_tree_view_calc_size (GtkTreeView *tree_view,
4815 GtkTreeViewColumn *column;
4817 gint vertical_separator;
4819 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4821 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4824 while (temp->left != tree->nil)
4830 /* Do stuff with node */
4831 for (list = tree_view->priv->columns; list; list = list->next)
4833 gint height = 0, width = 0;
4834 column = list->data;
4836 if (!column->visible)
4839 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4840 gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4841 max_height = MAX (max_height, vertical_separator + height);
4843 /* FIXME: I'm getting the width of all nodes here. )-: */
4844 if (column->dirty == FALSE)
4847 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4851 if (gtk_tree_view_is_expander_column (tree_view, column) &&
4852 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4853 _gtk_tree_view_column_set_width (column,
4854 MAX (column->width, depth * tree_view->priv->tab_offset + width));
4856 _gtk_tree_view_column_set_width (column, MAX (column->width, width));
4859 _gtk_rbtree_node_set_height (tree, temp, max_height);
4861 if (temp->children != NULL &&
4862 gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4863 gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
4864 temp = _gtk_rbtree_next (tree, temp);
4866 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4870 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
4875 GtkTreeViewColumn *column;
4877 gboolean retval = FALSE;
4883 for (list = tree_view->priv->columns; list; list = list->next)
4886 column = list->data;
4887 if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4889 if (!column->visible)
4892 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4896 gtk_tree_view_column_cell_get_size (column,
4898 &width, &tmpheight);
4899 *height = MAX (*height, tmpheight);
4903 gtk_tree_view_column_cell_get_size (column,
4907 if (gtk_tree_view_is_expander_column (tree_view, column) &&
4908 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4910 if (depth * tree_view->priv->tab_offset + width > column->width)
4912 column->dirty = TRUE;
4918 if (width > column->width)
4920 column->dirty = TRUE;
4930 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
4935 GtkRBNode *temp = tree->root;
4936 GtkTreeViewColumn *column;
4939 gboolean is_all_dirty;
4941 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4943 while (temp->left != tree->nil)
4948 TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
4949 is_all_dirty = TRUE;
4950 for (list = tree_view->priv->columns; list; list = list->next)
4952 column = list->data;
4953 if (column->dirty == FALSE)
4955 is_all_dirty = FALSE;
4963 gtk_tree_view_discover_dirty_iter (tree_view,
4967 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
4968 temp->children != NULL)
4969 gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
4970 temp = _gtk_rbtree_next (tree, temp);
4972 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4977 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
4980 gboolean dirty = FALSE;
4982 GtkTreeViewColumn *column;
4985 if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
4986 tree_view->priv->model)
4987 gtk_tree_view_setup_model (tree_view);
4989 for (list = tree_view->priv->columns; list; list = list->next)
4991 column = list->data;
4995 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5000 w = MAX (w, column->button->requisition.width);
5002 _gtk_tree_view_column_set_width (column, w);
5010 if (tree_view->priv->model == NULL)
5013 path = gtk_tree_path_new_root ();
5014 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
5016 gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
5017 _gtk_tree_view_update_size (tree_view);
5020 gtk_tree_path_free (path);
5022 for (list = tree_view->priv->columns; list; list = list->next)
5024 column = list->data;
5025 column->dirty = FALSE;
5029 /* Make sure the node is visible vertically */
5031 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
5037 /* We process updates because we want to clear old selected items when we scroll.
5038 * if this is removed, we get a "selection streak" at the bottom. */
5039 if (GTK_WIDGET_REALIZED (tree_view))
5040 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
5042 offset = _gtk_rbtree_node_find_offset (tree, node);
5044 /* we reverse the order, b/c in the unusual case of the
5045 * node's height being taller then the visible area, we'd rather
5046 * have the node flush to the top
5048 if (offset + GTK_RBNODE_GET_HEIGHT (node) >
5049 tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
5050 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5051 offset + GTK_RBNODE_GET_HEIGHT (node) -
5052 tree_view->priv->vadjustment->page_size);
5053 if (offset < tree_view->priv->vadjustment->value)
5054 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5059 /* This function could be more efficient.
5060 * I'll optimize it if profiling seems to imply that
5064 _gtk_tree_view_find_path (GtkTreeView *tree_view,
5069 GtkRBTree *tmp_tree;
5070 GtkRBNode *tmp_node, *last;
5073 path = gtk_tree_path_new ();
5075 g_return_val_if_fail (node != NULL, path);
5076 g_return_val_if_fail (node != tree->nil, path);
5078 count = 1 + node->left->count;
5081 tmp_node = node->parent;
5085 while (tmp_node != tmp_tree->nil)
5087 if (tmp_node->right == last)
5088 count += 1 + tmp_node->left->count;
5090 tmp_node = tmp_node->parent;
5092 gtk_tree_path_prepend_index (path, count - 1);
5093 last = tmp_tree->parent_node;
5094 tmp_tree = tmp_tree->parent_tree;
5097 count = 1 + last->left->count;
5098 tmp_node = last->parent;
5104 /* Returns TRUE if we ran out of tree before finding the path.
5107 _gtk_tree_view_find_node (GtkTreeView *tree_view,
5112 GtkRBNode *tmpnode = NULL;
5113 GtkRBTree *tmptree = tree_view->priv->tree;
5114 gint *indices = gtk_tree_path_get_indices (path);
5115 gint depth = gtk_tree_path_get_depth (path);
5125 if (tmptree == NULL)
5131 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5139 tmptree = tmpnode->children;
5145 gtk_tree_view_is_expander_column (GtkTreeView *tree_view,
5146 GtkTreeViewColumn *column)
5150 if (tree_view->priv->expander_column != NULL)
5152 if (tree_view->priv->expander_column == column)
5158 for (list = tree_view->priv->columns; list; list = list->next)
5159 if (((GtkTreeViewColumn *)list->data)->visible)
5161 if (list && list->data == column)
5168 gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
5171 GtkMovementStep step,
5175 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
5177 GTK_TYPE_ENUM, step,
5178 GTK_TYPE_INT, count);
5180 gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
5182 GTK_TYPE_ENUM, step,
5183 GTK_TYPE_INT, count);
5185 if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
5188 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
5190 GTK_TYPE_ENUM, step,
5191 GTK_TYPE_INT, count);
5193 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
5195 GTK_TYPE_ENUM, step,
5196 GTK_TYPE_INT, count);
5200 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
5205 gint retval = FALSE;
5208 g_return_val_if_fail (node != NULL, FALSE);
5213 GtkRBTree *new_tree;
5214 GtkRBNode *new_node;
5216 new_tree = node->children;
5217 new_node = new_tree->root;
5219 while (new_node && new_node->left != new_tree->nil)
5220 new_node = new_node->left;
5222 g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE);
5223 retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
5226 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
5228 gtk_tree_model_unref_node (model, iter);
5229 node = _gtk_rbtree_next (tree, node);
5231 while (gtk_tree_model_iter_next (model, iter));
5237 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
5246 while (node && node->left != tree->nil)
5249 g_return_val_if_fail (node != NULL, FALSE);
5250 path = _gtk_tree_view_find_path (tree_view, tree, node);
5251 gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
5253 retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
5254 gtk_tree_path_free (path);
5260 gtk_tree_view_set_column_drag_info (GtkTreeView *tree_view,
5261 GtkTreeViewColumn *column)
5263 GtkTreeViewColumn *left_column;
5264 GtkTreeViewColumn *cur_column = NULL;
5265 GtkTreeViewColumnReorder *reorder;
5270 /* We want to precalculate the motion list such that we know what column slots
5275 /* First, identify all possible drop spots */
5276 tmp_list = tree_view->priv->columns;
5280 g_assert (tmp_list);
5282 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5283 tmp_list = tmp_list->next;
5285 if (cur_column->visible == FALSE)
5288 /* If it's not the column moving and func tells us to skip over the column, we continue. */
5289 if (left_column != column && cur_column != column &&
5290 tree_view->priv->column_drop_func &&
5291 ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5293 left_column = cur_column;
5296 reorder = g_new (GtkTreeViewColumnReorder, 1);
5297 reorder->left_column = left_column;
5298 left_column = reorder->right_column = cur_column;
5300 tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5303 /* Add the last one */
5304 if (tree_view->priv->column_drop_func == NULL ||
5305 ((left_column != column) &&
5306 (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
5308 reorder = g_new (GtkTreeViewColumnReorder, 1);
5309 reorder->left_column = left_column;
5310 reorder->right_column = NULL;
5311 tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5314 /* We quickly check to see if it even makes sense to reorder columns. */
5315 /* If there is nothing that can be moved, then we return */
5317 if (tree_view->priv->column_drag_info == NULL)
5320 /* We know there are always 2 slots possbile, as you can always return column. */
5321 /* If that's all there is, return */
5322 if (tree_view->priv->column_drag_info->next->next == NULL &&
5323 ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
5324 ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
5326 for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5327 g_free (tmp_list->data);
5328 g_list_free (tree_view->priv->column_drag_info);
5329 tree_view->priv->column_drag_info = NULL;
5332 /* We fill in the ranges for the columns, now that we've isolated them */
5333 left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5335 for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5337 reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
5339 reorder->left_align = left;
5340 if (tmp_list->next != NULL)
5342 g_assert (tmp_list->next->data);
5343 left = reorder->right_align = (reorder->right_column->button->allocation.x +
5344 reorder->right_column->button->allocation.width +
5345 ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
5351 gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
5352 reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5358 _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
5359 GtkTreeViewColumn *column)
5361 GdkEvent send_event;
5362 GtkAllocation allocation;
5363 gint x, y, width, height;
5365 g_return_if_fail (tree_view->priv->column_drag_info == NULL);
5367 gtk_tree_view_set_column_drag_info (tree_view, column);
5369 if (tree_view->priv->column_drag_info == NULL)
5372 if (tree_view->priv->drag_window == NULL)
5374 GdkWindowAttr attributes;
5375 guint attributes_mask;
5377 attributes.window_type = GDK_WINDOW_CHILD;
5378 attributes.wclass = GDK_INPUT_OUTPUT;
5379 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
5380 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
5381 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
5382 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
5384 tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
5387 gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
5390 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5391 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5393 gtk_grab_remove (column->button);
5395 send_event.crossing.type = GDK_LEAVE_NOTIFY;
5396 send_event.crossing.send_event = TRUE;
5397 send_event.crossing.window = column->button->window;
5398 send_event.crossing.subwindow = NULL;
5399 send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
5400 send_event.crossing.time = GDK_CURRENT_TIME;
5402 gtk_propagate_event (column->button, &send_event);
5404 send_event.button.type = GDK_BUTTON_RELEASE;
5405 send_event.button.window = GDK_ROOT_PARENT ();
5406 send_event.button.send_event = TRUE;
5407 send_event.button.time = GDK_CURRENT_TIME;
5408 send_event.button.x = -1;
5409 send_event.button.y = -1;
5410 send_event.button.axes = NULL;
5411 send_event.button.state = 0;
5412 send_event.button.button = 1;
5413 send_event.button.device = gdk_core_pointer;
5414 send_event.button.x_root = 0;
5415 send_event.button.y_root = 0;
5417 gtk_propagate_event (column->button, &send_event);
5419 gdk_window_move_resize (tree_view->priv->drag_window,
5420 column->button->allocation.x,
5421 column->button->allocation.y + column->button->allocation.height,
5422 column->button->allocation.width,
5423 column->button->allocation.height);
5424 gdk_window_reparent (column->button->window, tree_view->priv->drag_window, 0, 0);
5425 tree_view->priv->drag_column_x = column->button->allocation.x;
5426 allocation = column->button->allocation;
5428 gtk_widget_size_allocate (column->button, &allocation);
5429 gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
5431 tree_view->priv->drag_column = column;
5432 gdk_window_show (tree_view->priv->drag_window);
5434 gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
5435 gdk_window_get_size (tree_view->priv->header_window, &width, &height);
5437 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5438 while (gtk_events_pending ())
5439 gtk_main_iteration ();
5441 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
5442 gdk_pointer_grab (tree_view->priv->drag_window,
5444 GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
5445 NULL, NULL, GDK_CURRENT_TIME);
5446 gdk_keyboard_grab (tree_view->priv->drag_window,
5453 gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
5456 GdkRectangle *clip_rect)
5460 if (!GTK_WIDGET_REALIZED (tree_view))
5464 rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
5466 rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
5467 rect.height = BACKGROUND_HEIGHT (node);
5471 GdkRectangle new_rect;
5473 gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
5475 gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
5479 gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
5484 gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
5486 GdkRectangle *clip_rect)
5488 GtkRBTree *tree = NULL;
5489 GtkRBNode *node = NULL;
5491 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5494 gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
5497 /* x and y are the mouse position
5500 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
5510 gint vertical_separator;
5511 gint expander_height;
5513 gtk_widget_style_get (GTK_WIDGET (tree_view),
5514 "vertical_separator", &vertical_separator,
5515 "expander_height", &expander_height,
5518 if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
5521 widget = GTK_WIDGET (tree_view);
5523 gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
5526 area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
5527 area.width = tree_view->priv->tab_offset - 2;
5528 area.height = CELL_HEIGHT (node, vertical_separator);
5530 if (node == tree_view->priv->button_pressed_node)
5532 if (x >= area.x && x <= (area.x + area.width) &&
5533 y >= area.y && y <= (area.y + area.height))
5534 state = GTK_STATE_ACTIVE;
5536 state = GTK_STATE_NORMAL;
5540 if (node == tree_view->priv->prelight_node &&
5541 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
5542 state = GTK_STATE_PRELIGHT;
5544 state = GTK_STATE_NORMAL;
5547 gtk_paint_expander (widget->style,
5548 tree_view->priv->bin_window,
5554 (area.y + (area.height - expander_height) / 2 - (area.height + 1) % 2),
5555 node->children != NULL);
5560 _gtk_tree_view_update_col_width (GtkTreeView *tree_view)
5562 GList *list, *last_column;
5563 GtkTreeViewColumn *column;
5566 for (last_column = g_list_last (tree_view->priv->columns);
5568 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
5569 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
5570 last_column = last_column->prev)
5573 if (last_column == NULL)
5576 for (list = tree_view->priv->columns; list != last_column; list = list->next)
5578 column = GTK_TREE_VIEW_COLUMN (list->data);
5579 if (! column->visible)
5582 width += column->width;
5583 column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
5585 column = GTK_TREE_VIEW_COLUMN (last_column->data);
5586 column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
5590 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
5593 GtkTreePath *cursor_path;
5595 if ((tree_view->priv->tree == NULL) ||
5596 (! GTK_WIDGET_REALIZED (tree_view)))
5599 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
5600 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5603 if (tree_view->priv->cursor)
5604 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5606 if (cursor_path == NULL)
5608 GtkTreePath *tmp_path = gtk_tree_path_new_root ();
5609 /* FIXME: Get the first one visible!!! */
5610 if (tree_view->priv->cursor)
5611 gtk_tree_row_reference_free (tree_view->priv->cursor);
5613 tree_view->priv->cursor =
5614 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
5615 cursor_path = tmp_path;
5618 if (tree_view->priv->selection->type == GTK_TREE_SELECTION_SINGLE)
5619 gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
5621 gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
5622 gtk_tree_path_free (cursor_path);
5626 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
5629 GtkRBTree *cursor_tree = NULL;
5630 GtkRBNode *cursor_node = NULL;
5631 GtkRBTree *new_cursor_tree = NULL;
5632 GtkRBNode *new_cursor_node = NULL;
5633 GtkTreePath *cursor_path = NULL;
5636 if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
5639 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5640 _gtk_tree_view_find_node (tree_view, cursor_path,
5641 &cursor_tree, &cursor_node);
5642 gtk_tree_path_free (cursor_path);
5645 _gtk_rbtree_prev_full (cursor_tree, cursor_node,
5646 &new_cursor_tree, &new_cursor_node);
5648 _gtk_rbtree_next_full (cursor_tree, cursor_node,
5649 &new_cursor_tree, &new_cursor_node);
5651 if (new_cursor_node)
5653 cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
5654 gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
5655 gtk_tree_path_free (cursor_path);
5659 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5662 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5666 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
5669 GtkRBTree *cursor_tree = NULL;
5670 GtkRBNode *cursor_node = NULL;
5671 GtkTreePath *cursor_path = NULL;
5673 gint vertical_separator;
5675 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
5676 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5678 /* This is sorta weird. Focus in should give us a cursor */
5681 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5682 _gtk_tree_view_find_node (tree_view, cursor_path,
5683 &cursor_tree, &cursor_node);
5685 gtk_tree_path_free (cursor_path);
5687 g_return_if_fail (cursor_node != NULL);
5689 y = CELL_FIRST_PIXEL (tree_view, cursor_tree, cursor_node, vertical_separator);
5690 y += count * tree_view->priv->vadjustment->page_size;
5691 y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower, (gint)tree_view->priv->vadjustment->upper - vertical_separator);
5693 _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
5694 cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5695 g_return_if_fail (cursor_path != NULL);
5696 gtk_tree_view_real_set_cursor (tree_view,
5702 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
5705 GtkRBTree *cursor_tree = NULL;
5706 GtkRBNode *cursor_node = NULL;
5707 GtkTreePath *cursor_path = NULL;
5709 g_print ("gtk_tree_view_move_cursor_left_right\n");
5711 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
5712 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5716 _gtk_tree_view_find_node (tree_view, cursor_path,
5717 &cursor_tree, &cursor_node);
5718 gtk_tree_path_free (cursor_path);
5724 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
5727 GtkRBTree *cursor_tree;
5728 GtkRBNode *cursor_node;
5731 g_return_if_fail (tree_view->priv->tree != NULL);
5735 cursor_tree = tree_view->priv->tree;
5736 cursor_node = cursor_tree->root;
5737 while (cursor_node && cursor_node->left != cursor_tree->nil)
5738 cursor_node = cursor_node->left;
5742 cursor_tree = tree_view->priv->tree;
5743 cursor_node = cursor_tree->root;
5746 while (cursor_node && cursor_node->right != cursor_tree->nil)
5747 cursor_node = cursor_node->right;
5748 if (cursor_node->children == NULL)
5751 cursor_tree = cursor_node->children;
5752 cursor_node = cursor_tree->root;
5757 path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5758 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5762 FALSE?GDK_SHIFT_MASK:0);
5764 gtk_tree_row_reference_free (tree_view->priv->cursor);
5765 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
5766 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5770 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view)
5772 GtkRBTree *cursor_tree = NULL;
5773 GtkRBNode *cursor_node = NULL;
5774 GtkTreePath *cursor_path = NULL;
5777 if (tree_view->priv->cursor)
5778 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5780 if (cursor_path == NULL)
5783 _gtk_tree_view_find_node (tree_view, cursor_path,
5784 &cursor_tree, &cursor_node);
5785 if (cursor_tree == NULL)
5788 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5794 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5796 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5797 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5798 gtk_tree_path_free (cursor_path);
5802 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
5804 GtkRBTree *cursor_tree = NULL;
5805 GtkRBNode *cursor_node = NULL;
5806 GtkTreePath *cursor_path = NULL;
5809 if (tree_view->priv->cursor)
5810 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5812 if (cursor_path == NULL)
5815 _gtk_tree_view_find_node (tree_view, cursor_path,
5816 &cursor_tree, &cursor_node);
5817 if (cursor_tree == NULL)
5820 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5826 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5828 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5829 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5830 gtk_tree_path_free (cursor_path);
5836 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
5841 GtkTreePath *cursor_path = NULL;
5844 if (tree_view->priv->cursor)
5845 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5847 if (cursor_path == NULL)
5851 gtk_tree_view_expand_row (tree_view, cursor_path, open_all);
5853 gtk_tree_view_collapse_row (tree_view, cursor_path);
5855 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5856 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5857 gtk_tree_path_free (cursor_path);
5861 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
5863 GtkRBTree *cursor_tree = NULL;
5864 GtkRBNode *cursor_node = NULL;
5865 GtkTreePath *cursor_path = NULL;
5868 if (tree_view->priv->cursor)
5869 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5871 if (cursor_path == NULL)
5874 _gtk_tree_view_find_node (tree_view, cursor_path,
5875 &cursor_tree, &cursor_node);
5876 if (cursor_tree == NULL)
5879 if (cursor_tree->parent_node)
5881 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5882 cursor_node = cursor_tree->parent_node;
5883 cursor_tree = cursor_tree->parent_tree;
5885 gtk_tree_path_up (cursor_path);
5886 gtk_tree_row_reference_free (tree_view->priv->cursor);
5887 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
5888 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5895 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5897 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5898 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5899 gtk_tree_path_free (cursor_path);
5903 _gtk_tree_view_update_size (GtkTreeView *tree_view)
5907 GtkTreeViewColumn *column;
5908 gint vertical_separator;
5911 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5913 if (tree_view->priv->model == NULL)
5915 tree_view->priv->width = 0;
5916 tree_view->priv->height = 0;
5917 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5922 for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
5924 column = list->data;
5925 if (!column->visible)
5927 width += TREE_VIEW_COLUMN_WIDTH (column);
5930 if (tree_view->priv->tree == NULL)
5933 height = tree_view->priv->tree->root->offset + vertical_separator;
5935 if (tree_view->priv->width != width)
5937 tree_view->priv->width = width;
5938 tree_view->priv->hadjustment->upper = width;
5939 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
5942 if (tree_view->priv->height != height)
5944 tree_view->priv->height = height;
5945 tree_view->priv->vadjustment->upper = tree_view->priv->height;
5946 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
5949 if (GTK_WIDGET_REALIZED (tree_view))
5951 gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
5952 gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
5954 _gtk_tree_view_update_col_width (tree_view);
5957 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5960 /* this function returns the new width of the column being resized given
5961 * the column and x position of the cursor; the x cursor position is passed
5962 * in as a pointer and automagicly corrected if it's beyond min/max limits
5965 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
5969 GtkTreeViewColumn *column;
5972 /* first translate the x position from widget->window
5973 * to clist->clist_window
5976 column = g_list_nth (tree_view->priv->columns, i)->data;
5977 width = *x - column->button->allocation.x;
5979 /* Clamp down the value */
5980 if (column->min_width == -1)
5981 width = MAX (column->button->requisition.width,
5984 width = MAX (column->min_width,
5986 if (column->max_width != -1)
5987 width = MIN (width, column->max_width != -1);
5988 *x = column->button->allocation.x + width;
5996 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
5997 GtkTreeView *tree_view)
5999 if (GTK_WIDGET_REALIZED (tree_view))
6001 gdk_window_move (tree_view->priv->bin_window,
6002 - tree_view->priv->hadjustment->value,
6003 - tree_view->priv->vadjustment->value);
6004 gdk_window_move (tree_view->priv->header_window,
6005 - tree_view->priv->hadjustment->value,
6008 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6009 gdk_window_process_updates (tree_view->priv->header_window, TRUE);
6019 * gtk_tree_view_new:
6021 * Creates a new #GtkTreeView widget.
6023 * Return value: A newly created #GtkTreeView widget.
6026 gtk_tree_view_new (void)
6028 GtkTreeView *tree_view;
6030 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6032 return GTK_WIDGET (tree_view);
6036 * gtk_tree_view_new_with_model:
6037 * @model: the model.
6039 * Creates a new #GtkTreeView widget with the model initialized to @model.
6041 * Return value: A newly created #GtkTreeView widget.
6044 gtk_tree_view_new_with_model (GtkTreeModel *model)
6046 GtkTreeView *tree_view;
6048 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6049 gtk_tree_view_set_model (tree_view, model);
6051 return GTK_WIDGET (tree_view);
6058 * gtk_tree_view_get_model:
6059 * @tree_view: a #GtkTreeView
6061 * Returns the model the the #GtkTreeView is based on. Returns NULL if the
6064 * Return value: A #GtkTreeModel, or NULL if none is currently being used.
6067 gtk_tree_view_get_model (GtkTreeView *tree_view)
6069 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6071 return tree_view->priv->model;
6075 * gtk_tree_view_set_model:
6076 * @tree_view: A #GtkTreeNode.
6077 * @model: The model.
6079 * Sets the model for a #GtkTreeView. If the @tree_view already has a model
6080 * set, it will remove it before setting the new model. If @model is NULL, then
6081 * it will unset the old model.
6084 gtk_tree_view_set_model (GtkTreeView *tree_view,
6085 GtkTreeModel *model)
6087 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6089 if (model == tree_view->priv->model)
6093 g_object_ref (model);
6095 if (tree_view->priv->model != NULL)
6097 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
6099 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6100 G_SIGNAL_MATCH_DATA,
6103 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6104 G_SIGNAL_MATCH_DATA,
6107 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6108 G_SIGNAL_MATCH_DATA,
6111 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6112 G_SIGNAL_MATCH_DATA,
6115 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6116 G_SIGNAL_MATCH_DATA,
6119 if (tree_view->priv->tree)
6120 _gtk_rbtree_free (tree_view->priv->tree);
6123 if (tree_view->priv->drag_dest_row)
6124 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
6126 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
6127 g_object_unref (tree_view->priv->model);
6130 tree_view->priv->model = model;
6134 tree_view->priv->tree = NULL;
6135 if (GTK_WIDGET_REALIZED (tree_view))
6136 _gtk_tree_view_update_size (tree_view);
6138 else if (GTK_WIDGET_REALIZED (tree_view))
6140 gtk_tree_view_setup_model (tree_view);
6141 _gtk_tree_view_update_size (tree_view);
6144 g_object_notify (G_OBJECT (tree_view), "model");
6148 * gtk_tree_view_get_selection:
6149 * @tree_view: A #GtkTreeView.
6151 * Gets the #GtkTreeSelection associated with @tree_view.
6153 * Return value: A #GtkTreeSelection object.
6156 gtk_tree_view_get_selection (GtkTreeView *tree_view)
6158 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6160 return tree_view->priv->selection;
6164 * gtk_tree_view_get_hadjustment:
6165 * @tree_view: A #GtkTreeView
6167 * Gets the #GtkAdjustment currently being used for the horizontal aspect.
6169 * Return value: A #GtkAdjustment object, or NULL if none is currently being
6173 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
6175 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6177 if (tree_view->priv->hadjustment == NULL)
6178 gtk_tree_view_set_hadjustment (tree_view, NULL);
6180 return tree_view->priv->hadjustment;
6184 * gtk_tree_view_set_hadjustment:
6185 * @tree_view: A #GtkTreeView
6186 * @adjustment: The #GtkAdjustment to set, or NULL
6188 * Sets the #GtkAdjustment for the current horizontal aspect.
6191 gtk_tree_view_set_hadjustment (GtkTreeView *tree_view,
6192 GtkAdjustment *adjustment)
6194 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6196 gtk_tree_view_set_adjustments (tree_view,
6198 tree_view->priv->vadjustment);
6200 g_object_notify (G_OBJECT (tree_view), "hadjustment");
6204 * gtk_tree_view_get_vadjustment:
6205 * @tree_view: A #GtkTreeView
6207 * Gets the #GtkAdjustment currently being used for the vertical aspect.
6209 * Return value: A #GtkAdjustment object, or NULL if none is currently being
6213 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
6215 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6217 if (tree_view->priv->vadjustment == NULL)
6218 gtk_tree_view_set_vadjustment (tree_view, NULL);
6220 return tree_view->priv->vadjustment;
6224 * gtk_tree_view_set_vadjustment:
6225 * @tree_view: A #GtkTreeView
6226 * @adjustment: The #GtkAdjustment to set, or NULL
6228 * Sets the #GtkAdjustment for the current vertical aspect.
6231 gtk_tree_view_set_vadjustment (GtkTreeView *tree_view,
6232 GtkAdjustment *adjustment)
6234 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6236 gtk_tree_view_set_adjustments (tree_view,
6237 tree_view->priv->hadjustment,
6240 g_object_notify (G_OBJECT (tree_view), "vadjustment");
6243 /* Column and header operations */
6246 * gtk_tree_view_get_headers_visible:
6247 * @tree_view: A #GtkTreeView.
6249 * Returns TRUE if the headers on the @tree_view are visible.
6251 * Return value: Whether the headers are visible or not.
6254 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
6256 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6258 return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6262 * gtk_tree_view_set_headers_visible:
6263 * @tree_view: A #GtkTreeView.
6264 * @headers_visible: TRUE if the headers are visible
6266 * Sets the the visibility state of the headers.
6269 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
6270 gboolean headers_visible)
6274 GtkTreeViewColumn *column;
6276 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6278 headers_visible = !! headers_visible;
6280 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
6283 if (headers_visible)
6284 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6286 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6288 if (GTK_WIDGET_REALIZED (tree_view))
6290 gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
6291 if (headers_visible)
6293 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));
6295 if (GTK_WIDGET_MAPPED (tree_view))
6296 gtk_tree_view_map_buttons (tree_view);
6300 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
6302 for (list = tree_view->priv->columns; list; list = list->next)
6304 column = list->data;
6305 gtk_widget_unmap (column->button);
6307 gdk_window_hide (tree_view->priv->header_window);
6311 tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
6312 tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
6313 tree_view->priv->vadjustment->lower = 0;
6314 tree_view->priv->vadjustment->upper = tree_view->priv->height;
6315 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
6317 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6319 g_object_notify (G_OBJECT (tree_view), "headers_visible");
6324 * gtk_tree_view_columns_autosize:
6325 * @tree_view: A #GtkTreeView.
6327 * Resizes all columns to their optimal width.
6330 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
6332 gboolean dirty = FALSE;
6334 GtkTreeViewColumn *column;
6336 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6338 for (list = tree_view->priv->columns; list; list = list->next)
6340 column = list->data;
6341 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
6343 column->dirty = TRUE;
6348 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6352 * gtk_tree_view_set_headers_clickable:
6353 * @tree_view: A #GtkTreeView.
6354 * @setting: TRUE if the columns are clickable.
6356 * Allow the column title buttons to be clicked.
6359 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
6364 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6365 g_return_if_fail (tree_view->priv->model != NULL);
6367 for (list = tree_view->priv->columns; list; list = list->next)
6368 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
6370 g_object_notify (G_OBJECT (tree_view), "headers_clickable");
6375 * gtk_tree_view_set_rules_hint
6376 * @tree_view: a #GtkTreeView
6377 * @setting: %TRUE if the tree requires reading across rows
6379 * This function tells GTK+ that the user interface for your
6380 * application requires users to read across tree rows and associate
6381 * cells with one another. By default, GTK+ will then render the tree
6382 * with alternating row colors. <emphasis>DO NOT</emphasis> use it
6383 * just because you prefer the appearance of the ruled tree; that's a
6384 * question for the theme. Some themes will draw tree rows in
6385 * alternating colors even when rules are turned off, and users who
6386 * prefer that appearance all the time can choose those themes. You
6387 * should call this function only as a <emphasis>semantic</emphasis>
6388 * hint to the theme engine that your tree makes alternating colors
6389 * useful from a functional standpoint (since it has lots of columns,
6394 gtk_tree_view_set_rules_hint (GtkTreeView *tree_view,
6397 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6399 setting = setting != FALSE;
6401 if (tree_view->priv->has_rules != setting)
6403 tree_view->priv->has_rules = setting;
6404 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6407 g_object_notify (G_OBJECT (tree_view), "rules_hint");
6411 * gtk_tree_view_get_rules_hint
6412 * @tree_view: a #GtkTreeView
6414 * Gets the setting set by gtk_tree_view_set_rules_hint().
6416 * Return value: %TRUE if rules are useful for the user of this tree
6419 gtk_tree_view_get_rules_hint (GtkTreeView *tree_view)
6421 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6423 return tree_view->priv->has_rules;
6426 /* Public Column functions
6430 * gtk_tree_view_append_column:
6431 * @tree_view: A #GtkTreeView.
6432 * @column: The #GtkTreeViewColumn to add.
6434 * Appends @column to the list of columns.
6436 * Return value: The number of columns in @tree_view after appending.
6439 gtk_tree_view_append_column (GtkTreeView *tree_view,
6440 GtkTreeViewColumn *column)
6442 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6443 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6444 g_return_val_if_fail (column->tree_view == NULL, -1);
6446 return gtk_tree_view_insert_column (tree_view, column, -1);
6451 * gtk_tree_view_remove_column:
6452 * @tree_view: A #GtkTreeView.
6453 * @column: The #GtkTreeViewColumn to remove.
6455 * Removes @column from @tree_view.
6457 * Return value: The number of columns in @tree_view after removing.
6460 gtk_tree_view_remove_column (GtkTreeView *tree_view,
6461 GtkTreeViewColumn *column)
6463 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6464 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6465 g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
6467 _gtk_tree_view_column_unset_tree_view (column);
6469 if (tree_view->priv->focus_column == column)
6470 tree_view->priv->focus_column = NULL;
6472 tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
6474 tree_view->priv->n_columns--;
6476 if (GTK_WIDGET_REALIZED (tree_view))
6480 _gtk_tree_view_column_unrealize_button (column);
6481 for (list = tree_view->priv->columns; list; list = list->next)
6483 column = GTK_TREE_VIEW_COLUMN (list->data);
6484 if (column->visible)
6485 column->dirty = TRUE;
6488 if (tree_view->priv->n_columns == 0 &&
6489 gtk_tree_view_get_headers_visible (tree_view))
6490 gdk_window_hide (tree_view->priv->header_window);
6492 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6495 g_object_unref (G_OBJECT (column));
6496 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6498 return tree_view->priv->n_columns;
6502 * gtk_tree_view_insert_column:
6503 * @tree_view: A #GtkTreeView.
6504 * @column: The #GtkTreeViewColumn to be inserted.
6505 * @position: The position to insert @column in.
6507 * This inserts the @column into the @tree_view at @position. If @position is
6508 * -1, then the column is inserted at the end.
6510 * Return value: The number of columns in @tree_view after insertion.
6513 gtk_tree_view_insert_column (GtkTreeView *tree_view,
6514 GtkTreeViewColumn *column,
6517 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6518 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6519 g_return_val_if_fail (column->tree_view == NULL, -1);
6521 g_object_ref (G_OBJECT (column));
6523 if (tree_view->priv->n_columns == 0 &&
6524 GTK_WIDGET_REALIZED (tree_view) &&
6525 gtk_tree_view_get_headers_visible (tree_view))
6527 gdk_window_show (tree_view->priv->header_window);
6530 tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
6532 tree_view->priv->n_columns++;
6534 _gtk_tree_view_column_set_tree_view (column, tree_view);
6536 if (GTK_WIDGET_REALIZED (tree_view))
6540 _gtk_tree_view_column_realize_button (column);
6542 for (list = tree_view->priv->columns; list; list = list->next)
6544 column = GTK_TREE_VIEW_COLUMN (list->data);
6545 if (column->visible)
6546 column->dirty = TRUE;
6548 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6551 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6553 return tree_view->priv->n_columns;
6557 * gtk_tree_view_insert_column_with_attributes:
6558 * @tree_view: A #GtkTreeView
6559 * @position: The position to insert the new column in.
6560 * @title: The title to set the header to.
6561 * @cell: The #GtkCellRenderer.
6562 * @Varargs: A NULL terminated list of attributes.
6564 * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
6565 * @position. If @position is -1, then the newly created column is inserted at
6566 * the end. The column is initialized with the attributes given.
6568 * Return value: The number of columns in @tree_view after insertion.
6571 gtk_tree_view_insert_column_with_attributes (GtkTreeView *tree_view,
6574 GtkCellRenderer *cell,
6577 GtkTreeViewColumn *column;
6582 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6584 column = gtk_tree_view_column_new ();
6586 gtk_tree_view_column_set_title (column, title);
6587 gtk_tree_view_column_set_cell_renderer (column, cell);
6589 va_start (args, cell);
6591 attribute = va_arg (args, gchar *);
6593 while (attribute != NULL)
6595 column_id = va_arg (args, gint);
6596 gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
6597 attribute = va_arg (args, gchar *);
6602 gtk_tree_view_insert_column (tree_view, column, position);
6603 g_object_unref (column);
6605 return tree_view->priv->n_columns;
6609 * gtk_tree_view_insert_column_with_data_func:
6610 * @tree_view: a #GtkTreeView
6611 * @position: Position to insert, -1 for append
6612 * @title: column title
6613 * @cell: cell renderer for column
6614 * @func: function to set attributes of cell renderer
6615 * @data: data for @func
6616 * @dnotify: destroy notifier for @data
6618 * Convenience function that inserts a new column into the #GtkTreeView
6619 * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
6620 * attributes (normally using data from the model). See also
6621 * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_set_cell_renderer().
6623 * Return value: number of columns in the tree view post-insert
6626 gtk_tree_view_insert_column_with_data_func (GtkTreeView *tree_view,
6629 GtkCellRenderer *cell,
6630 GtkTreeCellDataFunc func,
6632 GDestroyNotify dnotify)
6634 GtkTreeViewColumn *column;
6636 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6638 column = gtk_tree_view_column_new ();
6640 gtk_tree_view_column_set_title (column, title);
6641 gtk_tree_view_column_set_cell_renderer (column, cell);
6642 gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
6644 gtk_tree_view_insert_column (tree_view, column, position);
6646 g_object_unref (column);
6648 return tree_view->priv->n_columns;
6652 * gtk_tree_view_get_column:
6653 * @tree_view: A #GtkTreeView.
6654 * @n: The position of the column, counting from 0.
6656 * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
6658 * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
6662 gtk_tree_view_get_column (GtkTreeView *tree_view,
6665 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6667 if (n < 0 || n >= tree_view->priv->n_columns)
6670 if (tree_view->priv->columns == NULL)
6673 return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
6677 * gtk_tree_view_get_columns:
6678 * @tree_view: A #GtkTreeView
6680 * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
6681 * The returned list must be freed with g_list_free ().
6683 * Return value: A list of #GtkTreeViewColumn s
6686 gtk_tree_view_get_columns (GtkTreeView *tree_view)
6688 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6690 return g_list_copy (tree_view->priv->columns);
6694 * gtk_tree_view_move_column_after:
6695 * @tree_view: A #GtkTreeView
6696 * @column: The #GtkTreeViewColumn to be moved.
6697 * @base_column: The #GtkTreeViewColumn to be moved relative to.
6699 * Moves @column to be after to @base_column. If @base_column is NULL, then
6700 * @column is placed in the first position.
6703 gtk_tree_view_move_column_after (GtkTreeView *tree_view,
6704 GtkTreeViewColumn *column,
6705 GtkTreeViewColumn *base_column)
6707 GList *column_list_el, *base_el = NULL;
6709 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6711 column_list_el = g_list_find (tree_view->priv->columns, column);
6712 g_return_if_fail (column_list_el != NULL);
6716 base_el = g_list_find (tree_view->priv->columns, base_column);
6717 g_return_if_fail (base_el != NULL);
6720 if (column_list_el->prev == base_el)
6723 tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
6724 if (base_el == NULL)
6726 column_list_el->prev = NULL;
6727 column_list_el->next = tree_view->priv->columns;
6728 if (column_list_el->next)
6729 column_list_el->next->prev = column_list_el;
6730 tree_view->priv->columns = column_list_el;
6734 column_list_el->prev = base_el;
6735 column_list_el->next = base_el->next;
6736 if (column_list_el->next)
6737 column_list_el->next->prev = column_list_el;
6738 base_el->next = column_list_el;
6741 if (GTK_WIDGET_REALIZED (tree_view))
6743 //gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6744 _gtk_tree_view_update_size (tree_view);
6745 gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view));
6748 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6752 * gtk_tree_view_set_expander_column:
6753 * @tree_view: A #GtkTreeView
6754 * @column: NULL, or the column to draw the expander arrow at.
6756 * Sets the column to draw the expander arrow at. It must be in @tree_view. If
6757 * @column is %NULL, then the expander arrow is fixed at the first column.
6760 gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
6761 GtkTreeViewColumn *column)
6763 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6765 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6767 if (tree_view->priv->expander_column != column)
6773 /* Confirm that column is in tree_view */
6774 for (list = tree_view->priv->columns; list; list = list->next)
6775 if (list->data == column)
6777 g_return_if_fail (list != NULL);
6780 tree_view->priv->expander_column = column;
6781 g_object_notify (G_OBJECT (tree_view), "expander_column");
6786 * gtk_tree_view_get_expander_column:
6787 * @tree_view: A #GtkTreeView
6789 * Returns the column that is the current expander column. This
6790 * column has the expander arrow drawn next to it.
6792 * Return value: The expander column.
6795 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
6797 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6799 return tree_view->priv->expander_column;
6804 * gtk_tree_view_set_column_drag_function:
6805 * @tree_view: A #GtkTreeView.
6806 * @func: A function to determine which columns are reorderable, or NULL.
6807 * @user_data: User data to be passed to @func, or NULL
6808 * @destroy: Destroy notifier for @user_data, or NULL
6810 * Sets a user function for determining where a column may be dropped when
6811 * dragged. This function is called on every column pair in turn at the
6812 * beginning of a column drag to determine where a drop can take place. The
6813 * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
6814 * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
6815 * @user_data. If either of the #GtkTreeViewColumn arguments for the drop spot
6816 * are NULL, then they indicate an edge. If @func is set to be NULL, then
6817 * @tree_view reverts to the default behavior of allowing all columns to be
6818 * dropped everywhere.
6821 gtk_tree_view_set_column_drag_function (GtkTreeView *tree_view,
6822 GtkTreeViewColumnDropFunc func,
6824 GtkDestroyNotify destroy)
6826 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6828 if (tree_view->priv->column_drop_func_data_destroy)
6829 (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
6831 tree_view->priv->column_drop_func = func;
6832 tree_view->priv->column_drop_func_data = user_data;
6833 tree_view->priv->column_drop_func_data_destroy = destroy;
6837 * gtk_tree_view_scroll_to_point:
6838 * @tree_view: a #GtkTreeView
6839 * @tree_x: X coordinate of new top-left pixel of visible area
6840 * @tree_y: Y coordinate of new top-left pixel of visible area
6842 * Scrolls the tree view such that the top-left corner of the visible
6843 * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
6844 * in tree window coordinates. The @tree_view must be realized before
6845 * this function is called. If it isn't, you probably want ot be
6846 * using gtk_tree_view_scroll_to_cell.
6849 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
6853 GtkAdjustment *hadj;
6854 GtkAdjustment *vadj;
6856 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6857 g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
6859 hadj = tree_view->priv->hadjustment;
6860 vadj = tree_view->priv->vadjustment;
6862 gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
6863 gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
6867 * gtk_tree_view_scroll_to_cell
6868 * @tree_view: A #GtkTreeView.
6869 * @path: The path of the row to move to.
6870 * @column: The #GtkTreeViewColumn to move horizontally to.
6871 * @row_align: The vertical alignment of the row specified by @path.
6872 * @col_align: The horizontal alignment of the column specified by @column.
6874 * Moves the alignments of @tree_view to the position specified by
6875 * @column and @path. If @column is NULL, then no horizontal
6876 * scrolling occurs. Likewise, if @path is NULL no vertical scrolling
6877 * occurs. @row_align determines where the row is placed, and
6878 * @col_align determines where @column is placed. Both are expected
6879 * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
6880 * right/bottom alignment, 0.5 means center.
6883 gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
6885 GtkTreeViewColumn *column,
6889 GdkRectangle cell_rect;
6890 GdkRectangle vis_rect;
6891 gint dest_x, dest_y;
6893 /* FIXME work on unmapped/unrealized trees? maybe implement when
6894 * we do incremental reflow for trees
6897 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6898 g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
6899 g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
6900 g_return_if_fail (path != NULL || column != NULL);
6902 row_align = CLAMP (row_align, 0.0, 1.0);
6903 col_align = CLAMP (col_align, 0.0, 1.0);
6905 if (! GTK_WIDGET_REALIZED (tree_view))
6908 tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
6910 tree_view->priv->scroll_to_column = column;
6911 tree_view->priv->scroll_to_row_align = row_align;
6912 tree_view->priv->scroll_to_col_align = col_align;
6917 gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
6918 gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
6920 dest_x = vis_rect.x;
6921 dest_y = vis_rect.y;
6925 dest_x = cell_rect.x +
6926 cell_rect.width * row_align -
6927 vis_rect.width * row_align;
6932 dest_y = cell_rect.y +
6933 cell_rect.height * col_align -
6934 vis_rect.height * col_align;
6937 gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
6942 * gtk_tree_view_row_activated:
6943 * @tree_view: A #GtkTreeView
6944 * @path: The #GtkTreePath to be activated.
6945 * @column: The #GtkTreeViewColumn to be activated.
6947 * Activates the cell determined by @path and @column.
6950 gtk_tree_view_row_activated (GtkTreeView *tree_view,
6952 GtkTreeViewColumn *column)
6954 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6956 /* FIXME: Actually activate the path internally, not just emit the signal */
6957 /* g_warning ("FIXME: Actually activate the path internally, not just emit the signal\n"); */
6958 g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
6963 gtk_tree_view_expand_all_helper (GtkRBTree *tree,
6967 GtkTreeView *tree_view = data;
6970 _gtk_rbtree_traverse (node->children,
6971 node->children->root,
6973 gtk_tree_view_expand_all_helper,
6975 else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
6981 node->children = _gtk_rbtree_new ();
6982 node->children->parent_tree = tree;
6983 node->children->parent_node = node;
6984 path = _gtk_tree_view_find_path (tree_view, tree, node);
6985 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6986 gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
6987 gtk_tree_view_build_tree (tree_view,
6990 gtk_tree_path_get_depth (path) + 1,
6992 GTK_WIDGET_REALIZED (tree_view));
6993 gtk_tree_path_free (path);
6998 * gtk_tree_view_expand_all:
6999 * @tree_view: A #GtkTreeView.
7001 * Recursively expands all nodes in the @tree_view.
7004 gtk_tree_view_expand_all (GtkTreeView *tree_view)
7006 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7007 g_return_if_fail (tree_view->priv->tree != NULL);
7009 _gtk_rbtree_traverse (tree_view->priv->tree,
7010 tree_view->priv->tree->root,
7012 gtk_tree_view_expand_all_helper,
7015 _gtk_tree_view_update_size (tree_view);
7019 gtk_tree_view_collapse_all_helper (GtkRBTree *tree,
7028 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
7030 node->children->root);
7031 gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
7034 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
7037 gtk_tree_path_get_depth (path));
7039 /* Ensure we don't have a dangling pointer to a dead node */
7040 ensure_unprelighted (GTK_TREE_VIEW (data));
7042 _gtk_rbtree_remove (node->children);
7043 gtk_tree_path_free (path);
7048 * gtk_tree_view_collapse_all:
7049 * @tree_view: A #GtkTreeView.
7051 * Recursively collapses all visible, expanded nodes in @tree_view.
7054 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
7056 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7057 g_return_if_fail (tree_view->priv->tree != NULL);
7059 _gtk_rbtree_traverse (tree_view->priv->tree,
7060 tree_view->priv->tree->root,
7062 gtk_tree_view_collapse_all_helper,
7065 if (GTK_WIDGET_MAPPED (tree_view))
7066 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7069 /* FIXME the bool return values for expand_row and collapse_row are
7070 * not analagous; they should be TRUE if the row had children and
7071 * was not already in the requested state.
7076 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
7089 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7090 if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
7093 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
7098 node->children = _gtk_rbtree_new ();
7099 node->children->parent_tree = tree;
7100 node->children->parent_node = node;
7102 gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
7104 gtk_tree_view_build_tree (tree_view,
7107 gtk_tree_path_get_depth (path) + 1,
7109 GTK_WIDGET_REALIZED (tree_view));
7111 if (GTK_WIDGET_MAPPED (tree_view))
7113 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7114 _gtk_tree_view_update_size (tree_view);
7117 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
7124 * gtk_tree_view_expand_row:
7125 * @tree_view: a #GtkTreeView
7126 * @path: path to a row
7127 * @open_all: whether to recursively expand, or just expand immediate children
7129 * Opens the row so its children are visible
7131 * Return value: %TRUE if the row existed and had children
7134 gtk_tree_view_expand_row (GtkTreeView *tree_view,
7141 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7142 g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
7143 g_return_val_if_fail (path != NULL, FALSE);
7145 if (_gtk_tree_view_find_node (tree_view,
7151 return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all);
7155 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
7161 GtkTreeIter children;
7164 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7166 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
7171 TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
7173 gtk_tree_view_discover_dirty (tree_view,
7176 gtk_tree_path_get_depth (path));
7178 /* Ensure we don't have a dangling pointer to a dead node */
7179 ensure_unprelighted (tree_view);
7181 if (tree_view->priv->destroy_count_func)
7183 gint child_count = 0;
7185 _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
7186 (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
7189 if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
7190 g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0);
7191 _gtk_rbtree_remove (node->children);
7193 if (GTK_WIDGET_MAPPED (tree_view))
7195 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7196 _gtk_tree_view_update_size (tree_view);
7199 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7201 GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7203 if (gtk_tree_path_is_ancestor (path, cursor_path))
7205 gtk_tree_row_reference_free (tree_view->priv->cursor);
7206 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7207 tree_view->priv->model,
7210 gtk_tree_path_free (cursor_path);
7213 if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
7215 GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
7216 if (gtk_tree_path_is_ancestor (path, anchor_path))
7218 gtk_tree_row_reference_free (tree_view->priv->anchor);
7219 tree_view->priv->anchor = NULL;
7221 gtk_tree_path_free (anchor_path);
7225 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
7231 * gtk_tree_view_collapse_row:
7232 * @tree_view: a #GtkTreeView
7233 * @path: path to a row in the @tree_view
7235 * Collapses a row (hides its child rows, if they exist.)
7237 * Return value: %TRUE if the row was collapsed.
7240 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
7246 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7247 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7248 g_return_val_if_fail (path != NULL, FALSE);
7250 if (_gtk_tree_view_find_node (tree_view,
7256 if (node->children == NULL)
7259 return gtk_tree_view_real_collapse_row (tree_view, path, tree, node);
7263 gtk_tree_view_map_expanded_rows_helper (GtkTreeView *tree_view,
7266 GtkTreeViewMappingFunc func,
7274 if (tree == NULL || tree->root == NULL)
7279 indices = gtk_tree_path_get_indices (path);
7280 depth = gtk_tree_path_get_depth (path);
7282 while (node && node->left != tree->nil)
7289 gtk_tree_path_append_index (path, 0);
7290 gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
7291 gtk_tree_path_up (path);
7292 (* func) (tree_view, path, user_data);
7295 indices[depth -1] = i;
7296 node = _gtk_rbtree_next (tree, node);
7301 * gtk_tree_view_map_expanded_rows:
7302 * @tree_view: A #GtkTreeView
7303 * @func: A function to be called
7304 * @data: User data to be passed to the function.
7306 * Calls @func on all expanded rows.
7309 gtk_tree_view_map_expanded_rows (GtkTreeView *tree_view,
7310 GtkTreeViewMappingFunc func,
7315 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7316 g_return_if_fail (func != NULL);
7318 path = gtk_tree_path_new_root ();
7320 gtk_tree_view_map_expanded_rows_helper (tree_view,
7321 tree_view->priv->tree,
7322 path, func, user_data);
7324 gtk_tree_path_free (path);
7328 * gtk_tree_view_row_expanded:
7329 * @tree_view: A #GtkTreeView.
7330 * @path: A #GtkTreePath to test expansion state.
7332 * Returns TRUE if the node pointed to by @path is expanded in @tree_view.
7334 * Return value: TRUE if #path is expanded.
7337 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
7343 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7344 g_return_val_if_fail (path != NULL, FALSE);
7346 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7351 return (node->children != NULL);
7354 static GtkTargetEntry row_targets[] = {
7355 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7360 * gtk_tree_view_get_reorderable:
7361 * @tree_view: a #GtkTreeView
7363 * Retrieves whether the user can reorder the tree via drag-and-drop. See
7364 * gtk_tree_view_set_reorderable().
7366 * Return value: %TRUE if the tree can be reordered.
7369 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
7371 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7373 return tree_view->priv->reorderable;
7377 * gtk_tree_view_set_reorderable:
7378 * @tree_view: A #GtkTreeView.
7379 * @reorderable: TRUE, if the tree can be reordered.
7381 * This function is a convenience function to allow you to reorder models that
7382 * support the #GtkDragSourceIface and the #GtkDragDestIface. Both
7383 * #GtkTreeStore and #GtkListStore support these. If @reorderable is TRUE, then
7384 * the user can reorder the model by dragging and dropping columns. The
7385 * developer will can listen to these changes by connecting to the model's
7388 * This function does not give you any degree of control over the order -- any
7389 * reorderering is allowed. If more control is needed, you should probably
7390 * handle drag and drop manually.
7393 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
7394 gboolean reorderable)
7396 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7398 if (tree_view->priv->reorderable == (reorderable?TRUE:FALSE))
7401 gtk_tree_view_set_rows_drag_source (tree_view,
7404 G_N_ELEMENTS (row_targets),
7407 gtk_tree_view_set_rows_drag_dest (tree_view,
7409 G_N_ELEMENTS (row_targets),
7413 g_object_notify (G_OBJECT (tree_view), "reorderable");
7417 gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
7419 gboolean clear_and_select)
7421 GtkRBTree *tree = NULL;
7422 GtkRBNode *node = NULL;
7424 if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7426 GtkTreePath *cursor_path;
7427 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7428 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7429 gtk_tree_path_free (cursor_path);
7431 gtk_tree_row_reference_free (tree_view->priv->cursor);
7433 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7434 tree_view->priv->model,
7436 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7440 if (clear_and_select && !tree_view->priv->in_free_motion)
7441 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7443 tree_view->priv->in_extended_selection?GDK_SHIFT_MASK:0);
7444 gtk_tree_view_clamp_node_visible (tree_view, tree, node);
7445 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
7449 * gtk_tree_view_set_cursor:
7450 * @tree_view: A #GtkTreeView
7451 * @path: A #GtkTreePath
7453 * Sets the current keyboard focus to be at @path, and selects it. This is
7454 * useful when you want to focus the user's attention on a particular row. If
7455 * you want to give the user keyboard focus in the tree_view, you should use
7456 * this function to set the correct path, and gtk_widget_grab_focus (GTK_WIDGET
7457 * (tree_view)) to actually give focus to the @tree_view.
7460 gtk_tree_view_set_cursor (GtkTreeView *tree_view,
7463 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7464 g_return_if_fail (path != NULL);
7466 gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
7471 * gtk_tree_view_get_path_at_pos:
7472 * @tree_view: A #GtkTreeView.
7473 * @window: The #GdkWindow to check against.
7474 * @x: The x position to be identified.
7475 * @y: The y position to be identified.
7476 * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
7477 * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
7478 * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
7479 * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
7481 * Finds the path at the point (@x, @y) relative to @window. If @window is
7482 * NULL, then the point is found relative to the widget coordinates. This
7483 * function is expected to be called after an event, with event->window being
7484 * passed in as @window. It is primarily for things like popup menus. If @path
7485 * is non-NULL, then it will be filled with the #GtkTreePath at that point.
7486 * This path should be freed with #gtk_tree_path_free. If @column is non-NULL,
7487 * then it will be filled with the column at that point. @cell_x and @cell_y
7488 * return the coordinates relative to the cell background (i.e. the
7489 * background_area passed to gtk_cell_renderer_render()). This function only
7490 * works if @tree_view is realized.
7492 * Return value: TRUE if a row exists at that coordinate.
7495 gtk_tree_view_get_path_at_pos (GtkTreeView *tree_view,
7500 GtkTreeViewColumn **column,
7508 g_return_val_if_fail (tree_view != NULL, FALSE);
7509 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7510 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
7513 g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
7520 if (x > tree_view->priv->hadjustment->upper)
7526 if (column || cell_x)
7528 GtkTreeViewColumn *tmp_column;
7529 GtkTreeViewColumn *last_column = NULL;
7531 gint remaining_x = x;
7532 gboolean found = FALSE;
7534 for (list = tree_view->priv->columns; list; list = list->next)
7536 tmp_column = list->data;
7538 if (tmp_column->visible == FALSE)
7541 last_column = tmp_column;
7542 if (remaining_x <= tmp_column->width)
7547 *column = tmp_column;
7550 *cell_x = remaining_x;
7554 remaining_x -= tmp_column->width;
7560 *column = last_column;
7563 *cell_x = last_column->width + remaining_x;
7569 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7570 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
7575 if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
7578 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7579 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
7590 *path = _gtk_tree_view_find_path (tree_view, tree, node);
7597 * gtk_tree_view_get_cell_area:
7598 * @tree_view: a #GtkTreeView
7599 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7600 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7601 * @rect: rectangle to fill with cell rect
7603 * Fills the bounding rectangle in tree window coordinates for the cell at the
7604 * row specified by @path and the column specified by @column. If @path is
7605 * %NULL, the y and height fields of the rectangle will be filled with 0. If
7606 * @column is %NULL, the x and width fields will be filled with 0. The sum of
7607 * all cell rects does not cover the entire tree; there are extra pixels in
7608 * between rows, for example. The returned rectangle is equivalent to the
7609 * @cell_area passed to gtk_cell_renderer_render(). This function is only valid
7610 * if #tree_view is realized.
7613 gtk_tree_view_get_cell_area (GtkTreeView *tree_view,
7615 GtkTreeViewColumn *column,
7618 GtkRBTree *tree = NULL;
7619 GtkRBNode *node = NULL;
7620 gint vertical_separator;
7622 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7623 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7624 g_return_if_fail (rect != NULL);
7626 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
7635 /* Get vertical coords */
7637 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7641 g_warning (G_STRLOC": no row corresponding to path");
7645 /* Remember that the rbtree stores node height including the vertical
7646 * separator, see comment at top of file.
7648 rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
7650 rect->height = CELL_HEIGHT (node, vertical_separator);
7657 gtk_tree_view_get_cell_xrange (tree_view, tree, column, &rect->x, &x2);
7658 rect->width = x2 - rect->x;
7663 * gtk_tree_view_get_background_area:
7664 * @tree_view: a #GtkTreeView
7665 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7666 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7667 * @rect: rectangle to fill with cell background rect
7669 * Fills the bounding rectangle in tree window coordinates for the
7670 * cell at the row specified by @path and the column specified by
7671 * @column. If @path is %NULL, the y and height fields of the
7672 * rectangle will be filled with 0. If @column is %NULL, the x and
7673 * width fields will be filled with 0. The returned rectangle is
7674 * equivalent to the @background_area passed to
7675 * gtk_cell_renderer_render(). These background areas tile to cover
7676 * the entire tree window (except for the area used for header
7677 * buttons). Contrast with the cell_area, returned by
7678 * gtk_tree_view_get_cell_area(), which returns only the cell itself,
7679 * excluding surrounding borders and the tree expander area.
7683 gtk_tree_view_get_background_area (GtkTreeView *tree_view,
7685 GtkTreeViewColumn *column,
7688 GtkRBTree *tree = NULL;
7689 GtkRBNode *node = NULL;
7691 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7692 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7693 g_return_if_fail (rect != NULL);
7702 /* Get vertical coords */
7704 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7708 g_warning (G_STRLOC": no row corresponding to path");
7712 rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
7714 rect->height = BACKGROUND_HEIGHT (node);
7721 gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
7722 rect->width = x2 - rect->x;
7727 * gtk_tree_view_get_visible_rect:
7728 * @tree_view: a #GtkTreeView
7729 * @visible_rect: rectangle to fill
7731 * Fills @visible_rect with the currently-visible region of the
7732 * buffer, in tree coordinates. Convert to widget coordinates with
7733 * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
7734 * 0,0 for row 0 of the tree, and cover the entire scrollable area of
7738 gtk_tree_view_get_visible_rect (GtkTreeView *tree_view,
7739 GdkRectangle *visible_rect)
7743 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7745 widget = GTK_WIDGET (tree_view);
7749 visible_rect->x = tree_view->priv->hadjustment->value;
7750 visible_rect->y = tree_view->priv->vadjustment->value;
7751 visible_rect->width = widget->allocation.width;
7752 visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7757 * gtk_tree_view_widget_to_tree_coords:
7758 * @tree_view: a #GtkTreeView
7759 * @wx: widget X coordinate
7760 * @wy: widget Y coordinate
7761 * @tx: return location for tree X coordinate
7762 * @ty: return location for tree Y coordinate
7764 * Converts widget coordinates to coordinates for the
7765 * tree window (the full scrollable area of the tree).
7769 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
7775 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7779 *tx = wx + tree_view->priv->hadjustment->value;
7784 *ty = wy + tree_view->priv->vadjustment->value;
7789 * gtk_tree_view_tree_to_widget_coords:
7790 * @tree_view: a #GtkTreeView
7791 * @tx: tree X coordinate
7792 * @ty: tree Y coordinate
7793 * @wx: return location for widget X coordinate
7794 * @wy: return location for widget Y coordinate
7796 * Converts tree coordinates (coordinates in full scrollable area of the tree)
7797 * to widget coordinates.
7801 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
7807 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7811 *wx = tx - tree_view->priv->hadjustment->value;
7816 *wy = ty - tree_view->priv->vadjustment->value;
7822 gtk_tree_view_set_rows_drag_source (GtkTreeView *tree_view,
7823 GdkModifierType start_button_mask,
7824 const GtkTargetEntry *targets,
7826 GdkDragAction actions,
7827 GtkTreeViewDraggableFunc row_draggable_func,
7830 TreeViewDragInfo *di;
7832 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7834 di = ensure_info (tree_view);
7835 clear_source_info (di);
7837 di->start_button_mask = start_button_mask;
7838 di->source_target_list = gtk_target_list_new (targets, n_targets);
7839 di->source_actions = actions;
7841 if (row_draggable_func)
7843 di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
7845 g_closure_ref (di->row_draggable_closure);
7846 g_closure_sink (di->row_draggable_closure);
7849 di->source_set = TRUE;
7853 gtk_tree_view_set_rows_drag_dest (GtkTreeView *tree_view,
7854 const GtkTargetEntry *targets,
7856 GdkDragAction actions,
7857 GtkTreeViewDroppableFunc location_droppable_func,
7860 TreeViewDragInfo *di;
7862 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7864 gtk_drag_dest_set (GTK_WIDGET (tree_view),
7870 di = ensure_info (tree_view);
7871 clear_dest_info (di);
7874 di->dest_target_list = gtk_target_list_new (targets, n_targets);
7876 if (location_droppable_func)
7878 di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
7880 g_closure_ref (di->location_droppable_closure);
7881 g_closure_sink (di->location_droppable_closure);
7884 di->dest_set = TRUE;
7888 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
7890 TreeViewDragInfo *di;
7892 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7894 di = get_info (tree_view);
7900 clear_source_info (di);
7901 di->source_set = FALSE;
7904 if (!di->dest_set && !di->source_set)
7905 remove_info (tree_view);
7910 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
7912 TreeViewDragInfo *di;
7914 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7916 di = get_info (tree_view);
7922 gtk_drag_dest_unset (GTK_WIDGET (tree_view));
7923 clear_dest_info (di);
7924 di->dest_set = FALSE;
7927 if (!di->dest_set && !di->source_set)
7928 remove_info (tree_view);
7933 gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
7935 GtkTreeViewDropPosition pos)
7937 GtkTreePath *current_dest;
7938 /* Note; this function is exported to allow a custom DND
7939 * implementation, so it can't touch TreeViewDragInfo
7942 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7944 current_dest = NULL;
7946 if (tree_view->priv->drag_dest_row)
7947 current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7951 gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
7952 gtk_tree_path_free (current_dest);
7955 if (tree_view->priv->drag_dest_row)
7956 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
7958 tree_view->priv->drag_dest_pos = pos;
7962 tree_view->priv->drag_dest_row =
7963 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
7964 gtk_tree_view_queue_draw_path (tree_view, path, NULL);
7967 tree_view->priv->drag_dest_row = NULL;
7971 gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
7973 GtkTreeViewDropPosition *pos)
7975 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7979 if (tree_view->priv->drag_dest_row)
7980 *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7986 *pos = tree_view->priv->drag_dest_pos;
7990 gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
7994 GtkTreeViewDropPosition *pos)
7997 gdouble offset_into_row;
8001 GtkTreeViewColumn *column = NULL;
8002 GtkTreePath *tmp_path = NULL;
8004 /* Note; this function is exported to allow a custom DND
8005 * implementation, so it can't touch TreeViewDragInfo
8008 g_return_val_if_fail (tree_view != NULL, FALSE);
8009 g_return_val_if_fail (drag_x >= 0, FALSE);
8010 g_return_val_if_fail (drag_y >= 0, FALSE);
8011 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
8017 if (tree_view->priv->tree == NULL)
8020 /* remember that drag_x and drag_y are in widget coords, convert to tree window */
8022 gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
8025 /* If in the top quarter of a row, we drop before that row; if
8026 * in the bottom quarter, drop after that row; if in the middle,
8027 * and the row has children, drop into the row.
8030 if (!gtk_tree_view_get_path_at_pos (tree_view,
8031 tree_view->priv->bin_window,
8039 gtk_tree_view_get_background_area (tree_view, tmp_path, column,
8042 offset_into_row = cell_y;
8047 gtk_tree_path_free (tmp_path);
8051 quarter = cell.height / 4.0;
8055 if (offset_into_row < quarter)
8057 *pos = GTK_TREE_VIEW_DROP_BEFORE;
8059 else if (offset_into_row < quarter * 2)
8061 *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
8063 else if (offset_into_row < quarter * 3)
8065 *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
8069 *pos = GTK_TREE_VIEW_DROP_AFTER;
8078 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
8080 * gtk_tree_view_create_row_drag_icon:
8081 * @tree_view: a #GtkTreeView
8082 * @path: a #GtkTreePath in @tree_view
8084 * Creates a GdkPixmap representation of the row at @path. This image is used
8087 * Return value: a newly allocatdd pixmap of the drag icon.
8090 gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
8098 GdkRectangle background_area;
8101 /* start drawing inside the black outline */
8103 GdkDrawable *drawable;
8104 gint bin_window_width;
8106 widget = GTK_WIDGET (tree_view);
8108 depth = gtk_tree_path_get_depth (path);
8110 _gtk_tree_view_find_node (tree_view,
8118 if (!gtk_tree_model_get_iter (tree_view->priv->model,
8125 background_area.y = y;
8126 background_area.height = BACKGROUND_HEIGHT (node);
8128 gdk_drawable_get_size (tree_view->priv->bin_window,
8129 &bin_window_width, NULL);
8131 drawable = gdk_pixmap_new (tree_view->priv->bin_window,
8132 bin_window_width + 2,
8133 background_area.height + 2,
8136 gdk_draw_rectangle (drawable,
8137 widget->style->base_gc [GTK_WIDGET_STATE (widget)],
8140 bin_window_width + 2,
8141 background_area.height + 2);
8143 gdk_draw_rectangle (drawable,
8144 widget->style->black_gc,
8147 bin_window_width + 1,
8148 background_area.height + 1);
8150 for (list = tree_view->priv->columns; list; list = list->next)
8152 GtkTreeViewColumn *column = list->data;
8153 GdkRectangle cell_area;
8154 gint vertical_separator;
8156 if (!column->visible)
8159 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter);
8161 background_area.x = cell_offset;
8162 background_area.width = column->displayed_width;
8164 cell_area = background_area;
8166 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
8167 cell_area.y += vertical_separator / 2;
8168 cell_area.height -= vertical_separator;
8170 if (gtk_tree_view_is_expander_column (tree_view, column) &&
8171 TREE_VIEW_DRAW_EXPANDERS(tree_view))
8173 cell_area.x += depth * tree_view->priv->tab_offset;
8174 cell_area.width -= depth * tree_view->priv->tab_offset;
8177 if (gtk_tree_view_column_cell_is_visible (column))
8178 gtk_tree_view_column_cell_render (column,
8185 cell_offset += column->displayed_width;
8193 * gtk_tree_view_set_destroy_count_func:
8194 * @tree_view: A #GtkTreeView
8195 * @func: Function to be called when a view row is destroyed, or NULL
8196 * @data: User data to be passed to @func, or NULL
8197 * @destroy: Destroy notifier for @data, or NULL
8199 * This function should almost never be used. It is meant for private use by
8200 * ATK for determining the number of visible children that are removed when the
8201 * user collapses a row, or a row is deleted.
8204 gtk_tree_view_set_destroy_count_func (GtkTreeView *tree_view,
8205 GtkTreeDestroyCountFunc func,
8207 GtkDestroyNotify destroy)
8209 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8211 if (tree_view->priv->destroy_count_destroy)
8212 (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
8214 tree_view->priv->destroy_count_func = func;
8215 tree_view->priv->destroy_count_data = data;
8216 tree_view->priv->destroy_count_destroy = destroy;