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 */
264 static void gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
267 GtkMovementStep step,
269 static void gtk_tree_view_unref_tree (GtkTreeView *tree_view,
271 static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
274 GdkRectangle *clip_rect);
275 static void gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
277 GdkRectangle *clip_rect);
278 static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
283 static void gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
286 static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view,
289 static void gtk_tree_view_ensure_scroll_timeout(GtkTreeView *tree_view,
291 static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
292 GtkTreeView *tree_view);
293 static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
297 static void gtk_tree_view_build_tree (GtkTreeView *tree_view,
302 gboolean calc_bounds);
303 static void gtk_tree_view_calc_size (GtkTreeView *priv,
307 static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
311 static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
315 static void gtk_tree_view_check_dirty (GtkTreeView *tree_view);
316 static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
319 static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
320 GdkEventMotion *event);
321 static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view);
324 static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view);
325 static void gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
327 static void gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
329 static void gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
331 static void gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
333 static gboolean gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
337 static gboolean gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
342 static void gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
344 gboolean clear_and_select,
345 GdkModifierType state);
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_uint ("expander_column",
494 _("Set the column number for the expander column"),
500 g_object_class_install_property (o_class,
502 g_param_spec_boolean ("reorderable",
504 _("View is reorderable"),
508 g_object_class_install_property (o_class,
510 g_param_spec_boolean ("rules_hint",
512 _("Set a hint to the theme engine to draw rows in alternating colors"),
516 /* Style properties */
517 /* the width of the column resize windows */
518 #define _TREE_VIEW_EXPANDER_WIDTH 14
519 #define _TREE_VIEW_EXPANDER_HEIGHT 14
520 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
521 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 0
523 gtk_widget_class_install_style_property (widget_class,
524 g_param_spec_int ("expander_width",
526 _("Width of the expander arrow"),
529 _TREE_VIEW_EXPANDER_WIDTH,
532 gtk_widget_class_install_style_property (widget_class,
533 g_param_spec_int ("expander_height",
534 _("Expander Height"),
535 _("Height of the expander arrow"),
538 _TREE_VIEW_EXPANDER_HEIGHT,
541 gtk_widget_class_install_style_property (widget_class,
542 g_param_spec_int ("vertical_separator",
543 _("Vertical Separator Width"),
544 _("Vertical space between cells"),
547 _TREE_VIEW_VERTICAL_SEPARATOR,
550 gtk_widget_class_install_style_property (widget_class,
551 g_param_spec_int ("horizontal_separator",
552 _("Horizontal Separator Width"),
553 _("Horizontal space between cells"),
556 _TREE_VIEW_HORIZONTAL_SEPARATOR,
560 widget_class->set_scroll_adjustments_signal =
561 gtk_signal_new ("set_scroll_adjustments",
563 GTK_CLASS_TYPE (object_class),
564 GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
565 gtk_marshal_VOID__OBJECT_OBJECT,
567 GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
569 tree_view_signals[ROW_ACTIVATED] =
570 gtk_signal_new ("row_activated",
571 GTK_RUN_LAST | GTK_RUN_ACTION,
572 GTK_CLASS_TYPE (object_class),
573 GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
574 gtk_marshal_VOID__BOXED_OBJECT,
577 GTK_TYPE_TREE_VIEW_COLUMN);
579 tree_view_signals[TEST_EXPAND_ROW] =
580 g_signal_newc ("test_expand_row",
581 G_TYPE_FROM_CLASS (object_class),
583 G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
584 _gtk_boolean_handled_accumulator, NULL,
585 gtk_marshal_BOOLEAN__BOXED_BOXED,
590 tree_view_signals[TEST_COLLAPSE_ROW] =
591 g_signal_newc ("test_collapse_row",
592 G_TYPE_FROM_CLASS (object_class),
594 G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
595 _gtk_boolean_handled_accumulator, NULL,
596 gtk_marshal_BOOLEAN__BOXED_BOXED,
601 tree_view_signals[ROW_EXPANDED] =
602 g_signal_newc ("row_expanded",
603 G_TYPE_FROM_CLASS (object_class),
605 G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
607 gtk_marshal_VOID__BOXED_BOXED,
612 tree_view_signals[ROW_COLLAPSED] =
613 g_signal_newc ("row_collapsed",
614 G_TYPE_FROM_CLASS (object_class),
616 G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
618 gtk_marshal_VOID__BOXED_BOXED,
623 tree_view_signals[COLUMNS_CHANGED] =
624 g_signal_newc ("columns_changed",
625 G_TYPE_FROM_CLASS (object_class),
627 G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
629 gtk_marshal_NONE__NONE,
632 tree_view_signals[BEGIN_EXTENDED_SELECTION] =
633 g_signal_newc ("begin_extended_selection",
634 G_TYPE_FROM_CLASS (object_class),
635 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
636 G_STRUCT_OFFSET (GtkTreeViewClass, begin_extended_selection),
638 gtk_marshal_NONE__NONE,
641 tree_view_signals[END_EXTENDED_SELECTION] =
642 g_signal_newc ("end_extended_selection",
643 G_TYPE_FROM_CLASS (object_class),
644 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
645 G_STRUCT_OFFSET (GtkTreeViewClass, end_extended_selection),
647 gtk_marshal_NONE__NONE,
650 tree_view_signals[BEGIN_FREE_MOTION] =
651 g_signal_newc ("begin_free_motion",
652 G_TYPE_FROM_CLASS (object_class),
653 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
654 G_STRUCT_OFFSET (GtkTreeViewClass, begin_free_motion),
656 gtk_marshal_NONE__NONE,
659 tree_view_signals[END_FREE_MOTION] =
660 g_signal_newc ("end_free_motion",
661 G_TYPE_FROM_CLASS (object_class),
662 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
663 G_STRUCT_OFFSET (GtkTreeViewClass, end_free_motion),
665 gtk_marshal_NONE__NONE,
668 tree_view_signals[MOVE_CURSOR] =
669 g_signal_newc ("move_cursor",
670 G_TYPE_FROM_CLASS (object_class),
671 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
672 G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
674 gtk_marshal_VOID__ENUM_INT,
675 GTK_TYPE_NONE, 2, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT);
677 tree_view_signals[SELECT_CURSOR_ROW] =
678 g_signal_newc ("select_cursor_row",
679 G_TYPE_FROM_CLASS (object_class),
680 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
681 G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
683 gtk_marshal_NONE__NONE,
686 tree_view_signals[TOGGLE_CURSOR_ROW] =
687 g_signal_newc ("toggle_cursor_row",
688 G_TYPE_FROM_CLASS (object_class),
689 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
690 G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
692 gtk_marshal_NONE__NONE,
695 tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
696 g_signal_newc ("expand_collapse_cursor_row",
697 G_TYPE_FROM_CLASS (object_class),
698 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
699 G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
701 gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
702 GTK_TYPE_NONE, 3, GTK_TYPE_BOOL, GTK_TYPE_BOOL, GTK_TYPE_BOOL);
704 tree_view_signals[SELECT_CURSOR_PARENT] =
705 g_signal_newc ("select_cursor_parent",
706 G_TYPE_FROM_CLASS (object_class),
707 G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
708 G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
710 gtk_marshal_NONE__NONE,
714 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, 0, "begin_extended_selection", 0);
715 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
716 gtk_binding_entry_add_signal (binding_set, GDK_Control_L, 0, "begin_free_motion", 0);
717 gtk_binding_entry_add_signal (binding_set, GDK_Control_L, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
718 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, 0, "begin_extended_selection", 0);
719 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
720 gtk_binding_entry_add_signal (binding_set, GDK_Control_R, 0, "begin_free_motion", 0);
721 gtk_binding_entry_add_signal (binding_set, GDK_Control_R, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
723 gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
724 GTK_MOVEMENT_DISPLAY_LINES, -1);
726 gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
727 GTK_MOVEMENT_DISPLAY_LINES, 1);
729 gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
730 GTK_MOVEMENT_DISPLAY_LINES, -1);
732 gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
733 GTK_MOVEMENT_DISPLAY_LINES, 1);
735 gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
736 GTK_MOVEMENT_BUFFER_ENDS, -1);
738 gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
739 GTK_MOVEMENT_BUFFER_ENDS, 1);
741 gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
742 GTK_MOVEMENT_PAGES, -1);
744 gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
745 GTK_MOVEMENT_PAGES, 1);
747 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
748 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
751 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
752 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
755 gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "move_cursor", 2,
756 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
759 gtk_binding_entry_add_signal (binding_set, GDK_b, GDK_CONTROL_MASK, "move_cursor", 2,
760 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
763 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
765 gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 0);
767 /* expand and collapse rows */
768 gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
769 GTK_TYPE_BOOL, FALSE,
771 GTK_TYPE_BOOL, FALSE);
772 /* Not doable on US keyboards */
773 gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
774 GTK_TYPE_BOOL, FALSE,
776 GTK_TYPE_BOOL, TRUE);
777 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
778 GTK_TYPE_BOOL, FALSE,
780 GTK_TYPE_BOOL, FALSE);
781 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
782 GTK_TYPE_BOOL, FALSE,
784 GTK_TYPE_BOOL, TRUE);
785 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
786 GTK_TYPE_BOOL, FALSE,
788 GTK_TYPE_BOOL, TRUE);
789 gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
792 GTK_TYPE_BOOL, TRUE);
794 gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
795 GTK_TYPE_BOOL, FALSE,
796 GTK_TYPE_BOOL, FALSE,
797 GTK_TYPE_BOOL, FALSE);
798 gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
799 GTK_TYPE_BOOL, FALSE,
800 GTK_TYPE_BOOL, FALSE,
801 GTK_TYPE_BOOL, TRUE);
802 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
803 GTK_TYPE_BOOL, FALSE,
804 GTK_TYPE_BOOL, FALSE,
805 GTK_TYPE_BOOL, FALSE);
806 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
807 GTK_TYPE_BOOL, FALSE,
808 GTK_TYPE_BOOL, FALSE,
809 GTK_TYPE_BOOL, TRUE);
810 gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
811 GTK_TYPE_BOOL, FALSE,
812 GTK_TYPE_BOOL, FALSE,
813 GTK_TYPE_BOOL, TRUE);
815 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
820 gtk_tree_view_init (GtkTreeView *tree_view)
822 tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
824 GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
826 tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
827 gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_width", &tree_view->priv->tab_offset, NULL);
828 tree_view->priv->n_columns = 0;
829 tree_view->priv->header_height = 1;
830 tree_view->priv->x_drag = 0;
831 tree_view->priv->drag_pos = -1;
832 tree_view->priv->header_has_focus = FALSE;
833 tree_view->priv->pressed_button = -1;
834 tree_view->priv->press_start_x = -1;
835 tree_view->priv->press_start_y = -1;
836 tree_view->priv->reorderable = FALSE;
837 gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
838 tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
839 _gtk_tree_view_update_size (tree_view);
849 gtk_tree_view_set_property (GObject *object,
854 GtkTreeView *tree_view;
856 tree_view = GTK_TREE_VIEW (object);
861 gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (g_value_get_object (value)));
863 case PROP_HADJUSTMENT:
864 gtk_tree_view_set_hadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
866 case PROP_VADJUSTMENT:
867 gtk_tree_view_set_vadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
869 case PROP_HEADERS_VISIBLE:
870 gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
872 case PROP_HEADERS_CLICKABLE:
873 gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
875 case PROP_EXPANDER_COLUMN:
876 gtk_tree_view_set_expander_column (tree_view, g_value_get_uint (value));
878 case PROP_REORDERABLE:
879 gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
881 case PROP_RULES_HINT:
882 gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
890 gtk_tree_view_get_property (GObject *object,
895 GtkTreeView *tree_view;
897 tree_view = GTK_TREE_VIEW (object);
902 g_value_set_object (value, G_OBJECT (tree_view->priv->model));
904 case PROP_HADJUSTMENT:
905 g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
907 case PROP_VADJUSTMENT:
908 g_value_set_object (value, G_OBJECT (tree_view->priv->vadjustment));
910 case PROP_HEADERS_VISIBLE:
911 g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
913 case PROP_EXPANDER_COLUMN:
914 g_value_set_uint (value, tree_view->priv->expander_column);
916 case PROP_REORDERABLE:
917 g_value_set_boolean (value, tree_view->priv->reorderable);
919 case PROP_RULES_HINT:
920 g_value_set_boolean (value, tree_view->priv->has_rules);
923 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
929 gtk_tree_view_finalize (GObject *object)
931 GtkTreeView *tree_view = (GtkTreeView *) object;
933 g_free (tree_view->priv);
935 if (G_OBJECT_CLASS (parent_class)->finalize)
936 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
945 gtk_tree_view_destroy (GtkObject *object)
947 GtkTreeView *tree_view = (GtkTreeView *) object;
951 if (tree_view->priv->tree != NULL)
953 gtk_tree_view_unref_tree (tree_view, tree_view->priv->tree);
954 _gtk_rbtree_free (tree_view->priv->tree);
955 tree_view->priv->tree = NULL;
958 if (tree_view->priv->model != NULL)
960 g_object_unref (G_OBJECT (tree_view->priv->model));
961 tree_view->priv->model = NULL;
964 if (tree_view->priv->columns != NULL)
966 for (list = tree_view->priv->columns; list; list = list->next)
967 g_object_unref (G_OBJECT (list->data));
968 g_list_free (tree_view->priv->columns);
969 tree_view->priv->columns = NULL;
972 if (tree_view->priv->selection != NULL)
974 _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
975 g_object_unref (tree_view->priv->selection);
976 tree_view->priv->selection = NULL;
979 if (tree_view->priv->anchor != NULL)
981 gtk_tree_row_reference_free (tree_view->priv->anchor);
982 tree_view->priv->anchor = NULL;
985 if (tree_view->priv->scroll_to_path != NULL)
987 gtk_tree_path_free (tree_view->priv->scroll_to_path);
988 tree_view->priv->scroll_to_path = NULL;
991 if (tree_view->priv->drag_dest_row != NULL)
993 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
994 tree_view->priv->drag_dest_row = NULL;
997 if (tree_view->priv->cursor)
999 gtk_tree_row_reference_free (tree_view->priv->cursor);
1000 tree_view->priv->cursor = NULL;
1003 if (tree_view->priv->column_drop_func_data &&
1004 tree_view->priv->column_drop_func_data_destroy)
1006 (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
1007 tree_view->priv->column_drop_func_data = NULL;
1010 if (GTK_OBJECT_CLASS (parent_class)->destroy)
1011 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1016 /* GtkWidget Methods
1019 /* GtkWidget::map helper */
1021 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1025 g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1027 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1029 GtkTreeViewColumn *column;
1031 for (list = tree_view->priv->columns; list; list = list->next)
1033 column = list->data;
1034 if (GTK_WIDGET_VISIBLE (column->button) &&
1035 !GTK_WIDGET_MAPPED (column->button))
1036 gtk_widget_map (column->button);
1038 for (list = tree_view->priv->columns; list; list = list->next)
1040 column = list->data;
1041 if (column->visible == FALSE)
1043 if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
1045 gdk_window_raise (column->window);
1046 gdk_window_show (column->window);
1049 gdk_window_hide (column->window);
1051 gdk_window_show (tree_view->priv->header_window);
1056 gtk_tree_view_map (GtkWidget *widget)
1059 GtkTreeView *tree_view;
1061 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1063 tree_view = GTK_TREE_VIEW (widget);
1065 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1067 tmp_list = tree_view->priv->children;
1070 GtkTreeViewChild *child = tmp_list->data;
1071 tmp_list = tmp_list->next;
1073 if (GTK_WIDGET_VISIBLE (child->widget))
1075 if (!GTK_WIDGET_MAPPED (child->widget))
1076 gtk_widget_map (child->widget);
1079 gdk_window_show (tree_view->priv->bin_window);
1081 gtk_tree_view_map_buttons (tree_view);
1083 gdk_window_show (widget->window);
1087 gtk_tree_view_realize (GtkWidget *widget)
1090 GtkTreeView *tree_view;
1092 GdkWindowAttr attributes;
1093 gint attributes_mask;
1095 g_return_if_fail (widget != NULL);
1096 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1098 tree_view = GTK_TREE_VIEW (widget);
1100 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
1101 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1103 /* Make the main, clipping window */
1104 attributes.window_type = GDK_WINDOW_CHILD;
1105 attributes.x = widget->allocation.x;
1106 attributes.y = widget->allocation.y;
1107 attributes.width = widget->allocation.width;
1108 attributes.height = widget->allocation.height;
1109 attributes.wclass = GDK_INPUT_OUTPUT;
1110 attributes.visual = gtk_widget_get_visual (widget);
1111 attributes.colormap = gtk_widget_get_colormap (widget);
1112 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1114 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1116 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1117 &attributes, attributes_mask);
1118 gdk_window_set_user_data (widget->window, widget);
1120 /* Make the window for the tree */
1123 attributes.width = tree_view->priv->width;
1124 attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
1125 attributes.event_mask = GDK_EXPOSURE_MASK |
1127 GDK_POINTER_MOTION_MASK |
1128 GDK_ENTER_NOTIFY_MASK |
1129 GDK_LEAVE_NOTIFY_MASK |
1130 GDK_BUTTON_PRESS_MASK |
1131 GDK_BUTTON_RELEASE_MASK |
1132 gtk_widget_get_events (widget);
1134 tree_view->priv->bin_window = gdk_window_new (widget->window,
1135 &attributes, attributes_mask);
1136 gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1138 /* Make the column header window */
1141 attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1142 attributes.height = tree_view->priv->header_height;
1143 attributes.event_mask = (GDK_EXPOSURE_MASK |
1145 GDK_BUTTON_PRESS_MASK |
1146 GDK_BUTTON_RELEASE_MASK |
1147 GDK_KEY_PRESS_MASK |
1148 GDK_KEY_RELEASE_MASK) |
1149 gtk_widget_get_events (widget);
1151 tree_view->priv->header_window = gdk_window_new (widget->window,
1152 &attributes, attributes_mask);
1153 gdk_window_set_user_data (tree_view->priv->header_window, widget);
1156 values.foreground = (widget->style->white.pixel==0 ?
1157 widget->style->black:widget->style->white);
1158 values.function = GDK_XOR;
1159 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1160 tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
1165 /* Add them all up. */
1166 widget->style = gtk_style_attach (widget->style, widget->window);
1167 gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1168 gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1169 gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1171 tmp_list = tree_view->priv->children;
1174 GtkTreeViewChild *child = tmp_list->data;
1175 tmp_list = tmp_list->next;
1177 gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1180 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1181 _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1183 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1185 if (tree_view->priv->scroll_to_path != NULL ||
1186 tree_view->priv->scroll_to_column != NULL)
1188 gtk_tree_view_scroll_to_cell (tree_view,
1189 tree_view->priv->scroll_to_path,
1190 tree_view->priv->scroll_to_column,
1191 tree_view->priv->scroll_to_row_align,
1192 tree_view->priv->scroll_to_col_align);
1193 if (tree_view->priv->scroll_to_path)
1195 gtk_tree_path_free (tree_view->priv->scroll_to_path);
1196 tree_view->priv->scroll_to_path = NULL;
1198 tree_view->priv->scroll_to_column = NULL;
1203 gtk_tree_view_unrealize (GtkWidget *widget)
1205 GtkTreeView *tree_view;
1208 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1210 tree_view = GTK_TREE_VIEW (widget);
1212 if (tree_view->priv->scroll_timeout != 0)
1214 gtk_timeout_remove (tree_view->priv->scroll_timeout);
1215 tree_view->priv->scroll_timeout = 0;
1218 if (tree_view->priv->open_dest_timeout != 0)
1220 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
1221 tree_view->priv->open_dest_timeout = 0;
1224 for (list = tree_view->priv->columns; list; list = list->next)
1225 _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1227 gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
1228 gdk_window_destroy (tree_view->priv->bin_window);
1229 tree_view->priv->bin_window = NULL;
1231 gdk_window_set_user_data (tree_view->priv->header_window, NULL);
1232 gdk_window_destroy (tree_view->priv->header_window);
1233 tree_view->priv->header_window = NULL;
1235 if (tree_view->priv->drag_window)
1237 gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
1238 gdk_window_destroy (tree_view->priv->drag_window);
1239 tree_view->priv->drag_window = NULL;
1242 if (tree_view->priv->drag_highlight_window)
1244 gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
1245 gdk_window_destroy (tree_view->priv->drag_highlight_window);
1246 tree_view->priv->drag_highlight_window = NULL;
1249 if (tree_view->priv->cursor_drag)
1251 gdk_cursor_destroy (tree_view->priv->cursor_drag);
1252 tree_view->priv->cursor_drag = NULL;
1255 if (tree_view->priv->xor_gc)
1257 gdk_gc_destroy (tree_view->priv->xor_gc);
1258 tree_view->priv->xor_gc = NULL;
1261 /* GtkWidget::unrealize destroys children and widget->window */
1262 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1263 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1266 /* GtkWidget::size_request helper */
1268 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
1272 tree_view->priv->header_height = 1;
1274 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
1276 for (list = tree_view->priv->columns; list; list = list->next)
1278 GtkRequisition requisition;
1279 GtkTreeViewColumn *column = list->data;
1281 if (column->button == NULL)
1284 column = list->data;
1286 gtk_widget_size_request (column->button, &requisition);
1288 _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
1289 tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1295 gtk_tree_view_size_request (GtkWidget *widget,
1296 GtkRequisition *requisition)
1298 GtkTreeView *tree_view;
1301 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1303 tree_view = GTK_TREE_VIEW (widget);
1305 requisition->width = tree_view->priv->width;
1306 requisition->height = tree_view->priv->height + tree_view->priv->header_height;
1308 tmp_list = tree_view->priv->children;
1312 GtkTreeViewChild *child = tmp_list->data;
1313 GtkRequisition child_requisition;
1315 tmp_list = tmp_list->next;
1317 if (GTK_WIDGET_VISIBLE (child->widget))
1318 gtk_widget_size_request (child->widget, &child_requisition);
1321 gtk_tree_view_size_request_buttons (tree_view);
1324 /* GtkWidget::size_allocate helper */
1326 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
1328 GtkTreeView *tree_view;
1330 GtkTreeViewColumn *column;
1331 GtkAllocation allocation;
1334 tree_view = GTK_TREE_VIEW (widget);
1337 allocation.height = tree_view->priv->header_height;
1339 for (list = tree_view->priv->columns; list != NULL; list = list->next)
1341 column = list->data;
1343 if (!column->visible)
1346 allocation.x = width;
1347 allocation.width = column->displayed_width;
1348 width += column->width;
1349 gtk_widget_size_allocate (column->button, &allocation);
1352 gdk_window_move_resize (column->window,
1353 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
1355 TREE_VIEW_DRAG_WIDTH, allocation.height);
1360 gtk_tree_view_size_allocate (GtkWidget *widget,
1361 GtkAllocation *allocation)
1364 GtkTreeView *tree_view;
1366 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1368 widget->allocation = *allocation;
1370 tree_view = GTK_TREE_VIEW (widget);
1372 gtk_tree_view_check_dirty (tree_view);
1374 tmp_list = tree_view->priv->children;
1378 GtkAllocation allocation;
1379 GtkRequisition requisition;
1381 GtkTreeViewChild *child = tmp_list->data;
1382 tmp_list = tmp_list->next;
1384 allocation.x = child->x;
1385 allocation.y = child->y;
1386 gtk_widget_get_child_requisition (child->widget, &requisition);
1387 allocation.width = requisition.width;
1388 allocation.height = requisition.height;
1390 gtk_widget_size_allocate (child->widget, &allocation);
1393 if (GTK_WIDGET_REALIZED (widget))
1395 gdk_window_move_resize (widget->window,
1396 allocation->x, allocation->y,
1397 allocation->width, allocation->height);
1398 gdk_window_resize (tree_view->priv->header_window,
1399 MAX (tree_view->priv->width, allocation->width),
1400 tree_view->priv->header_height);
1401 if (tree_view->priv->width < allocation->width)
1402 gdk_window_resize (tree_view->priv->bin_window,
1404 tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
1406 _gtk_tree_view_update_col_width (tree_view);
1409 gtk_tree_view_size_allocate_buttons (widget);
1411 tree_view->priv->hadjustment->page_size = allocation->width;
1412 tree_view->priv->hadjustment->page_increment = allocation->width;
1413 tree_view->priv->hadjustment->step_increment = allocation->width / 10;
1414 tree_view->priv->hadjustment->lower = 0;
1415 tree_view->priv->hadjustment->upper = tree_view->priv->width;
1417 if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
1418 tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
1419 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
1421 tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
1422 tree_view->priv->vadjustment->step_increment = (tree_view->priv->vadjustment->page_size) / 10;
1423 tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
1424 tree_view->priv->vadjustment->lower = 0;
1425 tree_view->priv->vadjustment->upper = tree_view->priv->height;
1427 if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
1428 gtk_adjustment_set_value (tree_view->priv->vadjustment,
1429 MAX (tree_view->priv->height - allocation->height, 0));
1431 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
1436 gtk_tree_view_button_press (GtkWidget *widget,
1437 GdkEventButton *event)
1439 GtkTreeView *tree_view;
1441 GtkTreeViewColumn *column = NULL;
1443 GdkRectangle background_area;
1444 GdkRectangle cell_area;
1445 gint vertical_separator;
1447 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1448 g_return_val_if_fail (event != NULL, FALSE);
1450 tree_view = GTK_TREE_VIEW (widget);
1451 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
1453 if (event->window == tree_view->priv->bin_window)
1462 GtkTreeViewColumn *column = NULL;
1464 if (!GTK_WIDGET_HAS_FOCUS (widget))
1465 gtk_widget_grab_focus (widget);
1466 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1468 /* are we in an arrow? */
1469 if (tree_view->priv->prelight_node &&
1470 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1472 if (event->button == 1)
1474 gtk_grab_add (widget);
1475 tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1476 tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1477 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1478 tree_view->priv->prelight_tree,
1479 tree_view->priv->prelight_node,
1486 /* find the node that was clicked */
1487 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1488 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1489 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1491 &node) + new_y - (gint)event->y;
1494 /* We clicked in dead space */
1497 /* Get the path and the node */
1498 path = _gtk_tree_view_find_path (tree_view, tree, node);
1499 depth = gtk_tree_path_get_depth (path);
1500 background_area.y = y_offset + event->y + vertical_separator;
1501 background_area.height = GTK_RBNODE_GET_HEIGHT (node) - vertical_separator;
1502 background_area.x = 0;
1504 /* Let the column have a chance at selecting it. */
1505 for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1509 column = list->data;
1511 if (!column->visible)
1514 background_area.width = column->displayed_width;
1515 if (i == tree_view->priv->expander_column &&
1516 TREE_VIEW_DRAW_EXPANDERS(tree_view))
1518 cell_area = background_area;
1519 cell_area.x += depth*tree_view->priv->tab_offset;
1520 cell_area.width -= depth*tree_view->priv->tab_offset;
1524 cell_area = background_area;
1527 if ((background_area.x > (gint) event->x) ||
1528 (background_area.y > (gint) event->y) ||
1529 (background_area.x + background_area.width <= (gint) event->x) ||
1530 (background_area.y + background_area.height <= (gint) event->y))
1532 background_area.x += background_area.width;
1536 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1537 gtk_tree_view_column_cell_set_cell_data (column,
1538 tree_view->priv->model,
1541 path_string = gtk_tree_path_to_string (path);
1543 if (gtk_tree_view_column_cell_event (column,
1549 g_free (path_string);
1550 gtk_tree_path_free (path);
1555 g_free (path_string);
1563 /* The columns didn't want the event. We handle it */
1565 /* Save press to possibly begin a drag
1567 if (tree_view->priv->pressed_button < 0)
1569 tree_view->priv->pressed_button = event->button;
1570 tree_view->priv->press_start_x = event->x;
1571 tree_view->priv->press_start_y = event->y;
1574 gtk_tree_view_real_set_cursor (tree_view, path, TRUE, event->state);
1576 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1578 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
1580 if (node->children == NULL)
1581 gtk_tree_view_real_expand_row (tree_view, path,
1584 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1587 gtk_tree_view_row_activated (tree_view, path, column);
1590 gtk_tree_path_free (path);
1594 /* We didn't click in the window. Let's check to see if we clicked on a column resize window.
1596 for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1598 column = list->data;
1599 if (event->window == column->window &&
1600 column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE &&
1605 if (gdk_pointer_grab (column->window, FALSE,
1606 GDK_POINTER_MOTION_HINT_MASK |
1607 GDK_BUTTON1_MOTION_MASK |
1608 GDK_BUTTON_RELEASE_MASK,
1609 NULL, NULL, event->time))
1612 gtk_grab_add (widget);
1613 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1615 /* block attached dnd signal handler */
1616 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1618 gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1620 if (!GTK_WIDGET_HAS_FOCUS (widget))
1621 gtk_widget_grab_focus (widget);
1623 tree_view->priv->drag_pos = i;
1624 tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1630 /* GtkWidget::button_release_event helper */
1632 gtk_tree_view_button_release_drag_column (GtkWidget *widget,
1633 GdkEventButton *event)
1635 GtkTreeView *tree_view;
1636 GtkAllocation allocation;
1638 tree_view = GTK_TREE_VIEW (widget);
1640 allocation = tree_view->priv->drag_column->button->allocation;
1641 allocation.x = tree_view->priv->drag_column_x;
1642 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1643 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
1644 gdk_window_reparent (tree_view->priv->drag_column->button->window,
1645 tree_view->priv->header_window,
1646 tree_view->priv->drag_column_x,
1647 tree_view->priv->drag_column->button->allocation.y);
1648 gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
1650 gtk_widget_size_allocate (tree_view->priv->drag_column->button, &allocation);
1651 gtk_widget_grab_focus (tree_view->priv->drag_column->button);
1653 if (tree_view->priv->cur_reorder &&
1654 tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
1655 gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
1656 tree_view->priv->cur_reorder->left_column);
1657 tree_view->priv->drag_column = NULL;
1658 gdk_window_hide (tree_view->priv->drag_window);
1660 g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
1661 g_list_free (tree_view->priv->column_drag_info);
1662 tree_view->priv->column_drag_info = NULL;
1664 gdk_window_hide (tree_view->priv->drag_highlight_window);
1666 /* Reset our flags */
1667 tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
1668 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
1673 /* GtkWidget::button_release_event helper */
1675 gtk_tree_view_button_release_column_resize (GtkWidget *widget,
1676 GdkEventButton *event)
1678 GtkTreeView *tree_view;
1684 tree_view = GTK_TREE_VIEW (widget);
1686 i = tree_view->priv->drag_pos;
1687 tree_view->priv->drag_pos = -1;
1689 /* unblock attached dnd signal handler */
1690 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1692 gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1694 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1695 gtk_widget_get_pointer (widget, &x, NULL);
1696 gtk_grab_remove (widget);
1697 gdk_pointer_ungrab (event->time);
1699 width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1700 _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1706 gtk_tree_view_button_release (GtkWidget *widget,
1707 GdkEventButton *event)
1709 GtkTreeView *tree_view;
1711 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1712 g_return_val_if_fail (event != NULL, FALSE);
1714 tree_view = GTK_TREE_VIEW (widget);
1716 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
1717 return gtk_tree_view_button_release_drag_column (widget, event);
1719 if (tree_view->priv->pressed_button == event->button)
1720 tree_view->priv->pressed_button = -1;
1722 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1723 return gtk_tree_view_button_release_column_resize (widget, event);
1725 if (tree_view->priv->button_pressed_node == NULL)
1728 if (event->button == 1)
1730 gtk_grab_remove (widget);
1731 if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1732 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1734 GtkTreePath *path = NULL;
1736 path = _gtk_tree_view_find_path (tree_view,
1737 tree_view->priv->button_pressed_tree,
1738 tree_view->priv->button_pressed_node);
1739 /* Actually activate the node */
1740 if (tree_view->priv->button_pressed_node->children == NULL)
1741 gtk_tree_view_real_expand_row (tree_view, path,
1742 tree_view->priv->button_pressed_tree,
1743 tree_view->priv->button_pressed_node,
1746 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1747 tree_view->priv->button_pressed_tree,
1748 tree_view->priv->button_pressed_node);
1749 gtk_tree_path_free (path);
1752 tree_view->priv->button_pressed_tree = NULL;
1753 tree_view->priv->button_pressed_node = NULL;
1760 /* GtkWidget::motion_event function set.
1764 coords_are_over_arrow (GtkTreeView *tree_view,
1767 /* these are in tree window coords */
1774 if (!GTK_WIDGET_REALIZED (tree_view))
1777 if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1780 arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
1782 arrow.height = BACKGROUND_HEIGHT (node);
1784 gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
1786 arrow.width = x2 - arrow.x;
1788 return (x >= arrow.x &&
1789 x < (arrow.x + arrow.height) &&
1791 y < (arrow.y + arrow.height));
1795 do_unprelight (GtkTreeView *tree_view,
1796 /* these are in tree window coords */
1800 if (tree_view->priv->prelight_node == NULL)
1803 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1805 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1806 !coords_are_over_arrow (tree_view,
1807 tree_view->priv->prelight_tree,
1808 tree_view->priv->prelight_node,
1811 /* We need to unprelight the old arrow. */
1813 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1815 gtk_tree_view_draw_arrow (tree_view,
1816 tree_view->priv->prelight_tree,
1817 tree_view->priv->prelight_node,
1823 tree_view->priv->prelight_node = NULL;
1824 tree_view->priv->prelight_tree = NULL;
1828 do_prelight (GtkTreeView *tree_view,
1831 /* these are in tree window coords */
1835 if (coords_are_over_arrow (tree_view, tree, node, x, y))
1836 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1838 tree_view->priv->prelight_node = node;
1839 tree_view->priv->prelight_tree = tree;
1841 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1845 ensure_unprelighted (GtkTreeView *tree_view)
1847 do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
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 (tree_view->priv->cursor == NULL)
2321 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2322 if (cursor_path == NULL)
2325 _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
2329 gtk_tree_path_free (cursor_path);
2333 gdk_drawable_get_size (tree_view->priv->bin_window,
2338 y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2339 gdk_drawable_get_size (tree_view->priv->bin_window,
2342 height = BACKGROUND_HEIGHT (node) - 1;
2343 if (tree_view->priv->focus_column != NULL)
2348 g_object_get (G_OBJECT (tree_view->priv->focus_column->cell),
2349 "can_activate", &can_focus,
2350 "visible", &visible,
2352 if (can_focus && visible)
2355 GdkRectangle cell_area;
2359 cell_area.x = tree_view->priv->focus_column->button->allocation.x;
2361 cell_area.width = tree_view->priv->focus_column->displayed_width;
2362 cell_area.height = CELL_HEIGHT (node, vertical_separator);
2364 gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
2365 gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column, tree_view->priv->model, &iter);
2367 gtk_cell_renderer_get_size (tree_view->priv->focus_column->cell, GTK_WIDGET (tree_view), &cell_area, &x_offset, &y_offset, &width, &height);
2370 x = cell_area.x + x_offset - 1;
2371 y = cell_area.y + y_offset - 1 + vertical_separator/2;
2375 gtk_paint_focus (widget->style,
2376 tree_view->priv->bin_window,
2380 x, y, width, height);
2382 gtk_tree_path_free (cursor_path);
2385 /* Warning: Very scary function.
2386 * Modify at your own risk
2389 gtk_tree_view_bin_expose (GtkWidget *widget,
2390 GdkEventExpose *event)
2392 GtkTreeView *tree_view;
2397 GtkRBNode *cursor = NULL;
2398 GtkRBTree *cursor_tree = NULL;
2399 GtkRBNode *drag_highlight = NULL;
2400 GtkRBTree *drag_highlight_tree = NULL;
2403 gint y_offset, x_offset, cell_offset;
2406 GdkRectangle background_area;
2407 GdkRectangle cell_area;
2410 gint bin_window_width;
2411 GtkTreePath *cursor_path;
2412 GtkTreePath *drag_dest_path;
2414 gint vertical_separator;
2416 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2418 tree_view = GTK_TREE_VIEW (widget);
2419 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2421 if (tree_view->priv->tree == NULL)
2424 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
2425 /* we want to account for a potential HEADER offset.
2426 * That is, if the header exists, we want to offset our event by its
2427 * height to find the right node.
2429 new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
2431 /* y_offset is the */
2433 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
2434 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2436 &node) + new_y - event->area.y;
2440 /* find the path for the node */
2441 path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
2444 gtk_tree_model_get_iter (tree_view->priv->model,
2447 depth = gtk_tree_path_get_depth (path);
2448 gtk_tree_path_free (path);
2451 drag_dest_path = NULL;
2453 if (tree_view->priv->cursor)
2454 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2457 _gtk_tree_view_find_node (tree_view, cursor_path,
2458 &cursor_tree, &cursor);
2460 if (tree_view->priv->drag_dest_row)
2461 drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
2464 _gtk_tree_view_find_node (tree_view, drag_dest_path,
2465 &drag_highlight_tree, &drag_highlight);
2467 gdk_drawable_get_size (tree_view->priv->bin_window,
2468 &bin_window_width, NULL);
2470 for (last_column = g_list_last (tree_view->priv->columns);
2472 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2473 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2474 last_column = last_column->prev)
2477 /* Actually process the expose event. To do this, we want to
2478 * start at the first node of the event, and walk the tree in
2479 * order, drawing each successive node.
2486 max_height = BACKGROUND_HEIGHT (node);
2488 x_offset = -event->area.x;
2490 highlight_x = 0; /* should match x coord of first cell */
2492 background_area.y = y_offset + event->area.y;
2493 background_area.height = max_height;
2496 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
2497 flags |= GTK_CELL_RENDERER_PRELIT;
2499 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
2500 flags |= GTK_CELL_RENDERER_SELECTED;
2502 parity = _gtk_rbtree_node_find_parity (tree, node);
2504 for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
2506 GtkTreeViewColumn *column = list->data;
2507 const gchar *detail = NULL;
2509 if (!column->visible)
2512 if (cell_offset > event->area.x + event->area.width ||
2513 cell_offset + column->displayed_width < event->area.x)
2515 cell_offset += column->displayed_width;
2519 if (column->show_sort_indicator)
2520 flags |= GTK_CELL_RENDERER_SORTED;
2522 flags &= ~GTK_CELL_RENDERER_SORTED;
2524 gtk_tree_view_column_cell_set_cell_data (column,
2525 tree_view->priv->model,
2528 background_area.x = cell_offset;
2529 background_area.width = column->displayed_width;
2531 cell_area = background_area;
2532 cell_area.y += vertical_separator / 2;
2533 cell_area.height -= vertical_separator;
2535 /* Select the detail for drawing the cell. relevant
2536 * factors are parity, sortedness, and whether to
2540 /* FIXME when we have style properties, clean this up.
2543 if (tree_view->priv->has_rules)
2545 if (flags & GTK_CELL_RENDERER_SORTED)
2548 detail = "cell_odd_ruled_sorted";
2550 detail = "cell_even_ruled_sorted";
2555 detail = "cell_odd_ruled";
2557 detail = "cell_even_ruled";
2562 if (flags & GTK_CELL_RENDERER_SORTED)
2565 detail = "cell_odd_sorted";
2567 detail = "cell_even_sorted";
2572 detail = "cell_odd";
2574 detail = "cell_even";
2580 /* Draw background */
2581 gtk_paint_flat_box (widget->style,
2583 (flags & GTK_CELL_RENDERER_SELECTED) ?
2584 GTK_STATE_SELECTED : GTK_STATE_NORMAL,
2591 background_area.width,
2592 background_area.height);
2594 if (i == tree_view->priv->expander_column &&
2595 TREE_VIEW_DRAW_EXPANDERS(tree_view))
2597 cell_area.x += depth*tree_view->priv->tab_offset;
2598 cell_area.width -= depth*tree_view->priv->tab_offset;
2600 /* If we have an expander column, the highlight underline
2601 * starts with that column, so that it indicates which
2602 * level of the tree we're dropping at.
2604 highlight_x = cell_area.x;
2606 gtk_tree_view_column_cell_render (column,
2612 if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
2615 gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
2616 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2624 gtk_tree_view_column_cell_render (column,
2631 cell_offset += column->displayed_width;
2634 if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
2635 gtk_tree_view_draw_focus (widget);
2637 if (node == drag_highlight)
2639 /* Draw indicator for the drop
2641 gint highlight_y = -1;
2642 GtkRBTree *tree = NULL;
2643 GtkRBNode *node = NULL;
2646 switch (tree_view->priv->drag_dest_pos)
2648 case GTK_TREE_VIEW_DROP_BEFORE:
2649 highlight_y = background_area.y - vertical_separator/2;
2652 case GTK_TREE_VIEW_DROP_AFTER:
2653 highlight_y = background_area.y + background_area.height + vertical_separator/2;
2656 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2657 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2658 _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
2662 gdk_drawable_get_size (tree_view->priv->bin_window,
2664 gtk_paint_focus (widget->style,
2665 tree_view->priv->bin_window,
2669 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
2670 width - 1, BACKGROUND_HEIGHT (node) - 1);
2675 if (highlight_y >= 0)
2677 gdk_draw_line (event->window,
2678 widget->style->black_gc,
2681 bin_window_width - highlight_x,
2686 y_offset += max_height;
2689 GtkTreeIter parent = iter;
2692 tree = node->children;
2695 g_assert (node != tree->nil);
2697 while (node->left != tree->nil)
2699 has_child = gtk_tree_model_iter_children (tree_view->priv->model,
2705 TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
2709 gboolean done = FALSE;
2712 node = _gtk_rbtree_next (tree, node);
2715 gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
2719 TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
2723 GtkTreeIter parent_iter = iter;
2724 gboolean has_parent;
2726 node = tree->parent_node;
2727 tree = tree->parent_tree;
2729 /* we've run out of tree. It's okay to return though, as
2730 * we'd only break out of the while loop below. */
2732 has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
2738 TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
2744 while (y_offset < event->area.height);
2747 gtk_tree_path_free (cursor_path);
2750 gtk_tree_path_free (drag_dest_path);
2756 gtk_tree_view_expose (GtkWidget *widget,
2757 GdkEventExpose *event)
2759 GtkTreeView *tree_view;
2761 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2763 tree_view = GTK_TREE_VIEW (widget);
2765 if (event->window == tree_view->priv->bin_window)
2766 return gtk_tree_view_bin_expose (widget, event);
2772 gtk_tree_view_key_press (GtkWidget *widget,
2775 GtkTreeView *tree_view = (GtkTreeView *) widget;
2777 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2779 if (event->keyval == GDK_Escape)
2781 tree_view->priv->cur_reorder = NULL;
2782 gtk_tree_view_button_release_drag_column (widget, NULL);
2786 return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
2789 /* FIXME Is this function necessary? Can I get an enter_notify event
2790 * w/o either an expose event or a mouse motion event?
2793 gtk_tree_view_enter_notify (GtkWidget *widget,
2794 GdkEventCrossing *event)
2796 GtkTreeView *tree_view;
2801 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2803 tree_view = GTK_TREE_VIEW (widget);
2805 /* Sanity check it */
2806 if (event->window != tree_view->priv->bin_window)
2809 if (tree_view->priv->tree == NULL)
2812 if ((tree_view->priv->button_pressed_node != NULL) &&
2813 (tree_view->priv->button_pressed_node != node))
2816 /* find the node internally */
2817 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2819 _gtk_rbtree_find_offset (tree_view->priv->tree,
2820 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2827 do_prelight (tree_view, tree, node, event->x, new_y);
2829 if (tree_view->priv->prelight_node)
2830 gtk_tree_view_queue_draw_node (tree_view,
2831 tree_view->priv->prelight_tree,
2832 tree_view->priv->prelight_node,
2839 gtk_tree_view_leave_notify (GtkWidget *widget,
2840 GdkEventCrossing *event)
2842 GtkTreeView *tree_view;
2844 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2846 tree_view = GTK_TREE_VIEW (widget);
2848 if (tree_view->priv->prelight_node)
2849 gtk_tree_view_queue_draw_node (tree_view,
2850 tree_view->priv->prelight_tree,
2851 tree_view->priv->prelight_node,
2854 ensure_unprelighted (tree_view);
2861 gtk_tree_view_focus_in (GtkWidget *widget,
2862 GdkEventFocus *event)
2864 GtkTreeView *tree_view;
2866 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2867 g_return_val_if_fail (event != NULL, FALSE);
2869 tree_view = GTK_TREE_VIEW (widget);
2871 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2873 gtk_widget_queue_draw (widget);
2880 gtk_tree_view_focus_out (GtkWidget *widget,
2881 GdkEventFocus *event)
2883 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2884 g_return_val_if_fail (event != NULL, FALSE);
2886 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2888 gtk_widget_queue_draw (widget);
2889 GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE;
2890 GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE;
2898 set_source_row (GdkDragContext *context,
2899 GtkTreeModel *model,
2900 GtkTreePath *source_row)
2902 g_object_set_data_full (G_OBJECT (context),
2903 "gtk-tree-view-source-row",
2904 source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
2905 (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
2909 get_source_row (GdkDragContext *context)
2911 GtkTreeRowReference *ref =
2912 g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
2915 return gtk_tree_row_reference_get_path (ref);
2922 set_dest_row (GdkDragContext *context,
2923 GtkTreeModel *model,
2924 GtkTreePath *dest_row)
2926 g_object_set_data_full (G_OBJECT (context),
2927 "gtk-tree-view-dest-row",
2928 dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
2929 (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
2933 get_dest_row (GdkDragContext *context)
2935 GtkTreeRowReference *ref =
2936 g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
2939 return gtk_tree_row_reference_get_path (ref);
2944 /* Get/set whether drag_motion requested the drag data and
2945 * drag_data_received should thus not actually insert the data,
2946 * since the data doesn't result from a drop.
2949 set_status_pending (GdkDragContext *context,
2950 GdkDragAction suggested_action)
2952 g_object_set_data (G_OBJECT (context),
2953 "gtk-tree-view-status-pending",
2954 GINT_TO_POINTER (suggested_action));
2957 static GdkDragAction
2958 get_status_pending (GdkDragContext *context)
2960 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
2961 "gtk-tree-view-status-pending"));
2964 static TreeViewDragInfo*
2965 get_info (GtkTreeView *tree_view)
2967 return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
2971 clear_source_info (TreeViewDragInfo *di)
2973 if (di->source_target_list)
2974 gtk_target_list_unref (di->source_target_list);
2976 if (di->row_draggable_closure)
2977 g_closure_unref (di->row_draggable_closure);
2979 di->source_target_list = NULL;
2980 di->row_draggable_closure = NULL;
2984 clear_dest_info (TreeViewDragInfo *di)
2986 if (di->location_droppable_closure)
2987 g_closure_unref (di->location_droppable_closure);
2989 if (di->dest_target_list)
2990 gtk_target_list_unref (di->dest_target_list);
2992 di->location_droppable_closure = NULL;
2993 di->dest_target_list = NULL;
2997 destroy_info (TreeViewDragInfo *di)
2999 clear_source_info (di);
3000 clear_dest_info (di);
3004 static TreeViewDragInfo*
3005 ensure_info (GtkTreeView *tree_view)
3007 TreeViewDragInfo *di;
3009 di = get_info (tree_view);
3013 di = g_new0 (TreeViewDragInfo, 1);
3015 g_object_set_data_full (G_OBJECT (tree_view),
3016 "gtk-tree-view-drag-info",
3018 (GDestroyNotify) destroy_info);
3025 remove_info (GtkTreeView *tree_view)
3027 g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
3031 drag_scan_timeout (gpointer data)
3033 GtkTreeView *tree_view;
3035 GdkModifierType state;
3036 GtkTreePath *path = NULL;
3037 GtkTreeViewColumn *column = NULL;
3038 GdkRectangle visible_rect;
3040 tree_view = GTK_TREE_VIEW (data);
3042 gdk_window_get_pointer (tree_view->priv->bin_window,
3045 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3047 /* See if we are near the edge. */
3048 if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
3049 (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
3050 (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
3051 (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
3053 gtk_tree_view_get_path_at_pos (tree_view,
3054 tree_view->priv->bin_window,
3063 gtk_tree_view_scroll_to_cell (tree_view,
3068 gtk_tree_path_free (path);
3077 remove_scroll_timeout (GtkTreeView *tree_view)
3079 if (tree_view->priv->scroll_timeout != 0)
3081 gtk_timeout_remove (tree_view->priv->scroll_timeout);
3082 tree_view->priv->scroll_timeout = 0;
3086 check_model_dnd (GtkTreeModel *model,
3087 GType required_iface,
3088 const gchar *signal)
3090 if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
3092 g_warning ("You must override the default '%s' handler "
3093 "on GtkTreeView when using models that don't support "
3094 "the %s interface and enabling drag-and-drop. The simplest way to do this "
3095 "is to connect to '%s' and call "
3096 "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
3097 "the default handler from running. Look at the source code "
3098 "for the default handler in gtktreeview.c to get an idea what "
3099 "your handler should do. (gtktreeview.c is in the GTK source "
3100 "code.) If you're using GTK from a language other than C, "
3101 "there may be a more natural way to override default handlers, e.g. via derivation.",
3102 signal, g_type_name (required_iface), signal);
3110 remove_open_timeout (GtkTreeView *tree_view)
3112 if (tree_view->priv->open_dest_timeout != 0)
3114 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
3115 tree_view->priv->open_dest_timeout = 0;
3121 open_row_timeout (gpointer data)
3123 GtkTreeView *tree_view = data;
3124 GtkTreePath *dest_path = NULL;
3125 GtkTreeViewDropPosition pos;
3127 gtk_tree_view_get_drag_dest_row (tree_view,
3132 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3133 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3135 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
3136 tree_view->priv->open_dest_timeout = 0;
3138 gtk_tree_path_free (dest_path);
3145 gtk_tree_path_free (dest_path);
3150 /* Returns TRUE if event should not be propagated to parent widgets */
3152 set_destination_row (GtkTreeView *tree_view,
3153 GdkDragContext *context,
3156 GdkDragAction *suggested_action,
3159 GtkTreePath *path = NULL;
3160 GtkTreeViewDropPosition pos;
3161 GtkTreeViewDropPosition old_pos;
3162 TreeViewDragInfo *di;
3164 GtkTreePath *old_dest_path = NULL;
3166 *suggested_action = 0;
3169 widget = GTK_WIDGET (tree_view);
3171 di = get_info (tree_view);
3175 /* someone unset us as a drag dest, note that if
3176 * we return FALSE drag_leave isn't called
3179 gtk_tree_view_set_drag_dest_row (tree_view,
3181 GTK_TREE_VIEW_DROP_BEFORE);
3183 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3184 remove_open_timeout (GTK_TREE_VIEW (widget));
3186 return FALSE; /* no longer a drop site */
3189 *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
3190 if (*target == GDK_NONE)
3195 if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
3200 /* can't drop here */
3201 remove_open_timeout (tree_view);
3203 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3205 GTK_TREE_VIEW_DROP_BEFORE);
3207 /* don't propagate to parent though */
3213 /* If we left the current row's "open" zone, unset the timeout for
3216 gtk_tree_view_get_drag_dest_row (tree_view,
3220 if (old_dest_path &&
3221 (gtk_tree_path_compare (path, old_dest_path) != 0 ||
3222 !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3223 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
3224 remove_open_timeout (tree_view);
3227 gtk_tree_path_free (old_dest_path);
3229 if (TRUE /* FIXME if the location droppable predicate */)
3231 GtkWidget *source_widget;
3233 *suggested_action = context->suggested_action;
3235 source_widget = gtk_drag_get_source_widget (context);
3237 if (source_widget == widget)
3239 /* Default to MOVE, unless the user has
3240 * pressed ctrl or alt to affect available actions
3242 if ((context->actions & GDK_ACTION_MOVE) != 0)
3243 *suggested_action = GDK_ACTION_MOVE;
3246 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3251 /* can't drop here */
3252 remove_open_timeout (tree_view);
3254 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3256 GTK_TREE_VIEW_DROP_BEFORE);
3262 get_logical_dest_row (GtkTreeView *tree_view)
3265 /* adjust path to point to the row the drop goes in front of */
3266 GtkTreePath *path = NULL;
3267 GtkTreeViewDropPosition pos;
3269 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3274 if (pos == GTK_TREE_VIEW_DROP_BEFORE)
3276 else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
3277 pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3279 /* get first child, drop before it */
3280 gtk_tree_path_append_index (path, 0);
3284 g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
3285 gtk_tree_path_next (path);
3292 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
3293 GdkEventMotion *event)
3295 GdkDragContext *context;
3296 TreeViewDragInfo *di;
3297 GtkTreePath *path = NULL;
3299 gint cell_x, cell_y;
3300 GtkTreeModel *model;
3302 di = get_info (tree_view);
3307 if (tree_view->priv->pressed_button < 0)
3310 if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
3311 tree_view->priv->press_start_x,
3312 tree_view->priv->press_start_y,
3313 event->x, event->y))
3316 model = gtk_tree_view_get_model (tree_view);
3321 button = tree_view->priv->pressed_button;
3322 tree_view->priv->pressed_button = -1;
3324 gtk_tree_view_get_path_at_pos (tree_view,
3325 tree_view->priv->bin_window,
3326 tree_view->priv->press_start_x,
3327 tree_view->priv->press_start_y,
3336 /* FIXME if the path doesn't match the row_draggable predicate,
3337 * return FALSE and free path
3340 /* FIXME Check whether we're a start button, if not return FALSE and
3344 context = gtk_drag_begin (GTK_WIDGET (tree_view),
3345 di->source_target_list,
3350 gtk_drag_set_icon_default (context);
3355 row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
3358 gtk_drag_set_icon_pixmap (context,
3359 gdk_drawable_get_colormap (row_pix),
3362 /* the + 1 is for the black border in the icon */
3363 tree_view->priv->press_start_x + 1,
3366 gdk_pixmap_unref (row_pix);
3369 set_source_row (context, model, path);
3370 gtk_tree_path_free (path);
3377 gtk_tree_view_drag_begin (GtkWidget *widget,
3378 GdkDragContext *context)
3384 gtk_tree_view_drag_end (GtkWidget *widget,
3385 GdkDragContext *context)
3390 /* Default signal implementations for the drag signals */
3392 gtk_tree_view_drag_data_get (GtkWidget *widget,
3393 GdkDragContext *context,
3394 GtkSelectionData *selection_data,
3398 GtkTreeView *tree_view;
3399 GtkTreeModel *model;
3400 TreeViewDragInfo *di;
3401 GtkTreePath *source_row;
3403 tree_view = GTK_TREE_VIEW (widget);
3405 model = gtk_tree_view_get_model (tree_view);
3410 di = get_info (GTK_TREE_VIEW (widget));
3415 source_row = get_source_row (context);
3417 if (source_row == NULL)
3420 /* We can implement the GTK_TREE_MODEL_ROW target generically for
3421 * any model; for DragSource models there are some other targets
3425 if (GTK_IS_TREE_DRAG_SOURCE (model) &&
3426 gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
3431 /* If drag_data_get does nothing, try providing row data. */
3432 if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3434 gtk_selection_data_set_tree_row (selection_data,
3440 gtk_tree_path_free (source_row);
3445 gtk_tree_view_drag_data_delete (GtkWidget *widget,
3446 GdkDragContext *context)
3448 TreeViewDragInfo *di;
3449 GtkTreeModel *model;
3450 GtkTreeView *tree_view;
3451 GtkTreePath *source_row;
3453 tree_view = GTK_TREE_VIEW (widget);
3454 model = gtk_tree_view_get_model (tree_view);
3456 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
3459 di = get_info (tree_view);
3464 source_row = get_source_row (context);
3466 if (source_row == NULL)
3469 gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
3472 gtk_tree_path_free (source_row);
3474 set_source_row (context, NULL, NULL);
3478 gtk_tree_view_drag_leave (GtkWidget *widget,
3479 GdkDragContext *context,
3482 TreeViewDragInfo *di;
3484 di = get_info (GTK_TREE_VIEW (widget));
3486 /* unset any highlight row */
3487 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3489 GTK_TREE_VIEW_DROP_BEFORE);
3491 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3492 remove_open_timeout (GTK_TREE_VIEW (widget));
3497 gtk_tree_view_drag_motion (GtkWidget *widget,
3498 GdkDragContext *context,
3503 GtkTreePath *path = NULL;
3504 GtkTreeViewDropPosition pos;
3505 GtkTreeView *tree_view;
3506 GdkDragAction suggested_action = 0;
3509 tree_view = GTK_TREE_VIEW (widget);
3511 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3514 // gtk_tree_view_ensure_scroll_timeout (tree_view);
3516 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3520 /* Can't drop here. */
3521 gdk_drag_status (context, 0, time);
3525 if (tree_view->priv->open_dest_timeout == 0 &&
3526 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3527 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3529 tree_view->priv->open_dest_timeout =
3530 gtk_timeout_add (500, open_row_timeout, tree_view);
3533 if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3535 /* Request data so we can use the source row when
3536 * determining whether to accept the drop
3538 set_status_pending (context, suggested_action);
3539 gtk_drag_get_data (widget, context, target, time);
3543 set_status_pending (context, 0);
3544 gdk_drag_status (context, suggested_action, time);
3549 gtk_tree_path_free (path);
3556 gtk_tree_view_drag_drop (GtkWidget *widget,
3557 GdkDragContext *context,
3562 GtkTreeView *tree_view;
3564 GdkDragAction suggested_action = 0;
3565 GdkAtom target = GDK_NONE;
3566 TreeViewDragInfo *di;
3567 GtkTreeModel *model;
3569 tree_view = GTK_TREE_VIEW (widget);
3571 model = gtk_tree_view_get_model (tree_view);
3573 remove_scroll_timeout (GTK_TREE_VIEW (widget));
3574 remove_open_timeout (GTK_TREE_VIEW (widget));
3576 di = get_info (tree_view);
3581 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
3584 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3587 path = get_logical_dest_row (tree_view);
3589 if (target != GDK_NONE && path != NULL)
3591 /* in case a motion had requested drag data, change things so we
3592 * treat drag data receives as a drop.
3594 set_status_pending (context, 0);
3596 set_dest_row (context, model, path);
3600 gtk_tree_path_free (path);
3602 /* Unset this thing */
3603 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3605 GTK_TREE_VIEW_DROP_BEFORE);
3607 if (target != GDK_NONE)
3609 gtk_drag_get_data (widget, context, target, time);
3617 gtk_tree_view_drag_data_received (GtkWidget *widget,
3618 GdkDragContext *context,
3621 GtkSelectionData *selection_data,
3626 TreeViewDragInfo *di;
3627 gboolean accepted = FALSE;
3628 GtkTreeModel *model;
3629 GtkTreeView *tree_view;
3630 GtkTreePath *dest_row;
3631 GdkDragAction suggested_action;
3633 tree_view = GTK_TREE_VIEW (widget);
3635 model = gtk_tree_view_get_model (tree_view);
3637 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
3640 di = get_info (tree_view);
3645 suggested_action = get_status_pending (context);
3647 if (suggested_action)
3649 /* We are getting this data due to a request in drag_motion,
3650 * rather than due to a request in drag_drop, so we are just
3651 * supposed to call drag_status, not actually paste in the
3654 path = get_logical_dest_row (tree_view);
3657 suggested_action = 0;
3659 if (suggested_action)
3661 GtkTreeModel *src_model = NULL;
3662 GtkTreePath *src_path = NULL;
3664 if (!gtk_selection_data_get_tree_row (selection_data,
3667 suggested_action = 0;
3669 if (suggested_action)
3671 if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
3675 suggested_action = 0;
3677 gtk_tree_path_free (src_path);
3681 gdk_drag_status (context, suggested_action, time);
3684 gtk_tree_path_free (path);
3686 /* If you can't drop, remove user drop indicator until the next motion */
3687 if (suggested_action == 0)
3688 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3690 GTK_TREE_VIEW_DROP_BEFORE);
3695 dest_row = get_dest_row (context);
3697 if (dest_row == NULL)
3700 if (selection_data->length >= 0)
3702 if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
3708 gtk_drag_finish (context,
3710 (context->action == GDK_ACTION_MOVE),
3713 gtk_tree_path_free (dest_row);
3716 set_dest_row (context, NULL, NULL);
3721 /* GtkContainer Methods
3726 gtk_tree_view_remove (GtkContainer *container,
3729 GtkTreeView *tree_view;
3730 GtkTreeViewChild *child = NULL;
3733 g_return_if_fail (GTK_IS_TREE_VIEW (container));
3735 tree_view = GTK_TREE_VIEW (container);
3737 tmp_list = tree_view->priv->children;
3740 child = tmp_list->data;
3741 if (child->widget == widget)
3743 gtk_widget_unparent (widget);
3745 tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
3746 g_list_free_1 (tmp_list);
3751 tmp_list = tmp_list->next;
3754 tmp_list = tree_view->priv->columns;
3758 GtkTreeViewColumn *column;
3759 column = tmp_list->data;
3760 if (column->button == widget)
3762 gtk_widget_unparent (widget);
3765 tmp_list = tmp_list->next;
3771 gtk_tree_view_forall (GtkContainer *container,
3772 gboolean include_internals,
3773 GtkCallback callback,
3774 gpointer callback_data)
3776 GtkTreeView *tree_view;
3777 GtkTreeViewChild *child = NULL;
3778 GtkTreeViewColumn *column;
3781 g_return_if_fail (GTK_IS_TREE_VIEW (container));
3782 g_return_if_fail (callback != NULL);
3784 tree_view = GTK_TREE_VIEW (container);
3786 tmp_list = tree_view->priv->children;
3789 child = tmp_list->data;
3790 tmp_list = tmp_list->next;
3792 (* callback) (child->widget, callback_data);
3794 if (include_internals == FALSE)
3797 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3799 column = tmp_list->data;
3802 (* callback) (column->button, callback_data);
3806 /* Returns TRUE if the focus is within the headers, after the focus operation is
3810 gtk_tree_view_header_focus (GtkTreeView *tree_view,
3811 GtkDirectionType dir)
3813 GtkWidget *focus_child;
3814 GtkContainer *container;
3816 GList *last_column, *first_column;
3819 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
3822 focus_child = GTK_CONTAINER (tree_view)->focus_child;
3823 container = GTK_CONTAINER (tree_view);
3825 last_column = g_list_last (tree_view->priv->columns);
3828 if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
3829 GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
3831 last_column = last_column->prev;
3834 /* No headers are visible, or are focusable. We can't focus in or out.
3836 if (last_column == NULL)
3839 first_column = tree_view->priv->columns;
3840 while (first_column)
3842 if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
3843 GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
3845 first_column = first_column->next;
3850 case GTK_DIR_TAB_BACKWARD:
3851 case GTK_DIR_TAB_FORWARD:
3854 if (focus_child == NULL)
3856 if (tree_view->priv->focus_column != NULL)
3857 focus_child = tree_view->priv->focus_column->button;
3859 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3860 gtk_widget_grab_focus (focus_child);
3867 if (focus_child == NULL)
3869 if (tree_view->priv->focus_column != NULL)
3870 focus_child = tree_view->priv->focus_column->button;
3871 else if (dir == GTK_DIR_LEFT)
3872 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3874 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3875 gtk_widget_grab_focus (focus_child);
3879 if (gtk_widget_child_focus (focus_child, dir))
3881 /* The focus moves inside the button. */
3882 /* This is probably a great example of bad UI */
3886 /* We need to move the focus among the row of buttons. */
3887 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3888 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3891 if (tmp_list == first_column && dir == GTK_DIR_LEFT)
3893 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3894 gtk_widget_grab_focus (focus_child);
3897 else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
3899 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3900 gtk_widget_grab_focus (focus_child);
3906 GtkTreeViewColumn *column;
3908 if (dir == GTK_DIR_RIGHT)
3909 tmp_list = tmp_list->next;
3911 tmp_list = tmp_list->prev;
3913 if (tmp_list == NULL)
3915 g_warning ("Internal button not found");
3918 column = tmp_list->data;
3919 if (column->button &&
3921 GTK_WIDGET_CAN_FOCUS (column->button))
3923 focus_child = column->button;
3924 gtk_widget_grab_focus (column->button);
3930 g_assert_not_reached ();
3934 /* if focus child is non-null, we assume it's been set to the current focus child
3938 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3939 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3942 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3944 /* If the following isn't true, then the view is smaller then the scrollpane.
3946 if ((focus_child->allocation.x + focus_child->allocation.width) <=
3947 (tree_view->priv->hadjustment->upper))
3949 /* Scroll to the button, if needed */
3950 if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
3951 (focus_child->allocation.x + focus_child->allocation.width))
3952 gtk_adjustment_set_value (tree_view->priv->hadjustment,
3953 focus_child->allocation.x + focus_child->allocation.width -
3954 tree_view->priv->hadjustment->page_size);
3955 else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
3956 gtk_adjustment_set_value (tree_view->priv->hadjustment,
3957 focus_child->allocation.x);
3961 return (focus_child != NULL);
3964 /* We make the assumption that if container->focus_child != NULL, the focus must
3965 * be in the header. For now, this is accurate. It may not be in the future.
3968 /* The sordid relationship between focus_column and scroll_column:
3970 * The focus_column represents the column that currently has keyboard focus, and
3971 * is used when navigating columns by keyboard. scroll_column is used for
3972 * handling scrolling by keyboard, such that in cases.
3975 gtk_tree_view_focus (GtkWidget *widget,
3976 GtkDirectionType direction)
3978 GtkTreeView *tree_view;
3979 GtkWidget *focus_child;
3980 GtkContainer *container;
3982 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3983 g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
3985 container = GTK_CONTAINER (widget);
3986 tree_view = GTK_TREE_VIEW (widget);
3988 if (!GTK_WIDGET_IS_SENSITIVE (container))
3991 focus_child = container->focus_child;
3993 /* Case 1. Headers currently have focus. */
4000 gtk_tree_view_header_focus (tree_view, direction);
4002 case GTK_DIR_TAB_BACKWARD:
4005 case GTK_DIR_TAB_FORWARD:
4007 if (tree_view->priv->tree == NULL)
4009 gtk_tree_view_focus_to_cursor (tree_view);
4014 /* Case 2. We don't have focus at all. */
4015 if (!GTK_WIDGET_HAS_FOCUS (container))
4017 if (tree_view->priv->tree == NULL &&
4018 (direction == GTK_DIR_TAB_BACKWARD ||
4019 direction == GTK_DIR_UP))
4020 return gtk_tree_view_header_focus (tree_view, direction);
4021 if (((direction == GTK_DIR_TAB_FORWARD) ||
4022 (direction == GTK_DIR_RIGHT) ||
4023 (direction == GTK_DIR_DOWN) ||
4024 (direction == GTK_DIR_LEFT)) &&
4025 gtk_tree_view_header_focus (tree_view, direction))
4028 if (tree_view->priv->tree == NULL)
4030 gtk_tree_view_focus_to_cursor (tree_view);
4034 /* Case 3. We have focus already. */
4035 if (tree_view->priv->tree == NULL)
4036 return gtk_tree_view_header_focus (tree_view, direction);
4038 if (direction == GTK_DIR_TAB_BACKWARD)
4039 return (gtk_tree_view_header_focus (tree_view, direction));
4040 else if (direction == GTK_DIR_TAB_FORWARD)
4043 /* Other directions caught by the keybindings */
4044 gtk_tree_view_focus_to_cursor (tree_view);
4050 gtk_tree_view_set_focus_child (GtkContainer *container,
4053 GtkTreeView *tree_view = GTK_TREE_VIEW (container);
4056 for (list = tree_view->priv->columns; list; list = list->next)
4058 if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
4060 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
4065 (* parent_class->set_focus_child) (container, child);
4069 gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
4070 GtkAdjustment *hadj,
4071 GtkAdjustment *vadj)
4073 gboolean need_adjust = FALSE;
4075 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4078 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4080 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4082 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4084 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4086 if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4088 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4089 gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4092 if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4094 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4095 gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4098 if (tree_view->priv->hadjustment != hadj)
4100 tree_view->priv->hadjustment = hadj;
4101 gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4102 gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4104 gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4105 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4110 if (tree_view->priv->vadjustment != vadj)
4112 tree_view->priv->vadjustment = vadj;
4113 gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4114 gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4116 gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4117 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4123 gtk_tree_view_adjustment_changed (NULL, tree_view);
4127 gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view)
4129 tree_view->priv->in_extended_selection = TRUE;
4133 gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view)
4135 tree_view->priv->in_extended_selection = FALSE;
4139 gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view)
4141 tree_view->priv->in_free_motion = TRUE;
4145 gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view)
4147 tree_view->priv->in_free_motion = FALSE;
4151 gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
4152 GtkMovementStep step,
4155 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4156 g_return_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
4157 step == GTK_MOVEMENT_VISUAL_POSITIONS ||
4158 step == GTK_MOVEMENT_DISPLAY_LINES ||
4159 step == GTK_MOVEMENT_PAGES ||
4160 step == GTK_MOVEMENT_BUFFER_ENDS);
4162 if (tree_view->priv->tree == NULL)
4165 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
4166 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
4170 /* currently we make no distinction. When we go bi-di, we need to */
4171 case GTK_MOVEMENT_LOGICAL_POSITIONS:
4172 case GTK_MOVEMENT_VISUAL_POSITIONS:
4173 gtk_tree_view_move_cursor_left_right (tree_view, count);
4175 case GTK_MOVEMENT_DISPLAY_LINES:
4176 gtk_tree_view_move_cursor_up_down (tree_view, count);
4178 case GTK_MOVEMENT_PAGES:
4179 gtk_tree_view_move_cursor_page_up_down (tree_view, count);
4181 case GTK_MOVEMENT_BUFFER_ENDS:
4182 gtk_tree_view_move_cursor_start_end (tree_view, count);
4185 g_assert_not_reached ();
4189 /* TreeModel Callbacks
4193 gtk_tree_view_range_changed (GtkTreeModel *model,
4196 GtkTreePath *end_path,
4197 GtkTreeIter *end_iter,
4200 GtkTreeView *tree_view = (GtkTreeView *)data;
4204 gboolean dirty_marked;
4205 gboolean free_path = FALSE;
4206 gint vertical_separator;
4209 g_return_if_fail (path != NULL || iter != NULL);
4211 gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
4215 path = gtk_tree_model_get_path (model, iter);
4218 else if (iter == NULL)
4219 gtk_tree_model_get_iter (model, iter, path);
4221 if (_gtk_tree_view_find_node (tree_view,
4225 /* We aren't actually showing the node */
4231 dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
4233 gtk_tree_path_get_depth (path),
4236 if (GTK_RBNODE_GET_HEIGHT (node) != height + vertical_separator)
4238 _gtk_rbtree_node_set_height (tree, node, height + vertical_separator);
4239 gtk_widget_queue_resize (GTK_WIDGET (data));
4243 gtk_widget_queue_resize (GTK_WIDGET (data));
4245 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
4249 gtk_tree_path_free (path);
4253 gtk_tree_view_inserted (GtkTreeModel *model,
4258 GtkTreeView *tree_view = (GtkTreeView *) data;
4260 GtkRBTree *tmptree, *tree;
4261 GtkRBNode *tmpnode = NULL;
4265 gboolean free_path = FALSE;
4267 if (tree_view->priv->tree == NULL)
4268 tree_view->priv->tree = _gtk_rbtree_new ();
4270 tmptree = tree = tree_view->priv->tree;
4271 g_return_if_fail (path != NULL || iter != NULL);
4275 path = gtk_tree_model_get_path (model, iter);
4278 else if (iter == NULL)
4279 gtk_tree_model_get_iter (model, iter, path);
4281 /* Update all row-references */
4282 gtk_tree_row_reference_inserted (G_OBJECT (data), path);
4284 depth = gtk_tree_path_get_depth (path);
4285 indices = gtk_tree_path_get_indices (path);
4287 /* First, find the parent tree */
4288 while (i < depth - 1)
4290 if (tmptree == NULL)
4292 /* We aren't showing the node */
4296 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
4297 if (tmpnode == NULL)
4299 g_warning ("A node was inserted with a parent that's not in the tree.\n" \
4300 "This possibly means that a GtkTreeModel inserted a child node\n" \
4301 "before the parent was inserted.");
4304 else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
4306 /* FIXME enforce correct behavior on model, probably */
4307 /* In theory, the model should have emitted has_child_toggled here. We
4308 * try to catch it anyway, just to be safe, in case the model hasn't.
4310 GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
4313 gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
4314 gtk_tree_path_free (tmppath);
4318 tmptree = tmpnode->children;
4327 gtk_tree_model_ref_node (tree_view->priv->model, iter);
4328 max_height = gtk_tree_view_insert_iter_height (tree_view,
4332 if (indices[depth - 1] == 0)
4334 tmpnode = _gtk_rbtree_find_count (tree, 1);
4335 _gtk_rbtree_insert_before (tree, tmpnode, max_height);
4339 tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
4340 _gtk_rbtree_insert_after (tree, tmpnode, max_height);
4343 _gtk_tree_view_update_size (tree_view);
4347 gtk_tree_path_free (path);
4351 gtk_tree_view_has_child_toggled (GtkTreeModel *model,
4356 GtkTreeView *tree_view = (GtkTreeView *)data;
4357 GtkTreeIter real_iter;
4361 gboolean free_path = FALSE;
4363 g_return_if_fail (path != NULL || iter != NULL);
4370 path = gtk_tree_model_get_path (model, iter);
4373 else if (iter == NULL)
4374 gtk_tree_model_get_iter (model, &real_iter, path);
4376 if (_gtk_tree_view_find_node (tree_view,
4380 /* We aren't actually showing the node */
4386 has_child = gtk_tree_model_iter_has_child (model, &real_iter);
4389 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
4393 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
4395 GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
4397 if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
4399 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4400 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
4404 for (list = tree_view->priv->columns; list; list = list->next)
4405 if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
4407 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
4411 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4415 /* FIXME: Just redraw the node */
4416 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4421 gtk_tree_path_free (path);
4425 gtk_tree_view_deleted (GtkTreeModel *model,
4429 GtkTreeView *tree_view = (GtkTreeView *)data;
4434 g_return_if_fail (path != NULL);
4436 if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
4442 gtk_tree_row_reference_deleted (G_OBJECT (data), path);
4444 /* next, update the selection */
4445 if (tree_view->priv->anchor)
4447 GtkTreePath *anchor_path;
4449 /* the row reference may not have been updated yet. If it has not,
4450 * then anchor_path and path being equal indicates that the anchor
4451 * row was deleted. If it has, then anchor_path == NULL indicates the
4452 * the anchor row was deleted.
4455 anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
4457 if (anchor_path == NULL ||
4458 gtk_tree_path_compare (path, anchor_path) == 0)
4460 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) &&
4461 tree_view->priv->selection)
4462 g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
4466 gtk_tree_path_free (anchor_path);
4469 for (list = tree_view->priv->columns; list; list = list->next)
4470 if (((GtkTreeViewColumn *)list->data)->visible &&
4471 ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4472 ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
4474 /* Ensure we don't have a dangling pointer to a dead node */
4475 ensure_unprelighted (tree_view);
4477 g_assert (tree_view->priv->prelight_node == NULL);
4479 if (tree->root->count == 1)
4481 if (tree_view->priv->tree == tree)
4482 tree_view->priv->tree = NULL;
4484 _gtk_rbtree_remove (tree);
4488 _gtk_rbtree_remove_node (tree, node);
4491 _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
4496 gtk_tree_view_reordered (GtkTreeModel *model,
4497 GtkTreePath *parent,
4502 GtkTreeView *tree_view = GTK_TREE_VIEW (data);
4507 len = gtk_tree_model_iter_n_children (model, iter);
4512 gtk_tree_row_reference_reordered (G_OBJECT (data),
4517 if (_gtk_tree_view_find_node (tree_view,
4523 /* We need to special case the parent path */
4525 tree = tree_view->priv->tree;
4527 tree = node->children;
4532 /* FIXME: we need to unprelight our tree, if it's prelit. */
4533 _gtk_rbtree_reorder (tree, new_order, len);
4535 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4539 /* Internal tree functions
4544 gtk_tree_view_get_background_xrange (GtkTreeView *tree_view,
4546 GtkTreeViewColumn *column,
4550 GtkTreeViewColumn *tmp_column = NULL;
4561 for (list = tree_view->priv->columns; list; list = list->next)
4563 tmp_column = list->data;
4565 if (tmp_column == column)
4568 if (tmp_column->visible)
4569 total_width += tmp_column->width;
4572 if (tmp_column != column)
4574 g_warning (G_STRLOC": passed-in column isn't in the tree");
4583 if (column->visible)
4584 *x2 = total_width + column->width;
4586 *x2 = total_width; /* width of 0 */
4591 gtk_tree_view_get_cell_xrange (GtkTreeView *tree_view,
4593 GtkTreeViewColumn *column,
4597 GtkTreeViewColumn *tmp_column = NULL;
4610 for (list = tree_view->priv->columns; list; list = list->next)
4612 tmp_column = list->data;
4614 if (tmp_column == column)
4617 if (tmp_column->visible)
4618 total_width += tmp_column->width;
4623 if (tmp_column != column)
4625 g_warning (G_STRLOC": passed-in column isn't in the tree");
4629 /* Remember we're getting the cell range, i.e. the cell_area passed
4630 * to the cell renderer.
4633 if (i == tree_view->priv->expander_column)
4634 total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
4641 if (column->visible)
4642 *x2 = total_width + column->displayed_width;
4644 *x2 = total_width; /* width of 0 */
4649 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
4655 GtkTreeViewColumn *tmp_column = NULL;
4661 for (list = tree_view->priv->columns; list; list = list->next)
4663 tmp_column = list->data;
4665 if (i == tree_view->priv->expander_column)
4667 x_offset = total_width;
4671 if (tmp_column->visible)
4672 total_width += tmp_column->width;
4680 if (tmp_column && tmp_column->visible)
4682 /* +1 because x2 isn't included in the range. */
4684 *x2 = x_offset + tree_view->priv->tab_offset + 1;
4688 /* return an empty range, the expander column is hidden */
4695 gtk_tree_view_setup_model (GtkTreeView *tree_view)
4700 tree_view->priv->tree = NULL;
4702 g_signal_connectc (tree_view->priv->model,
4704 (GCallback) gtk_tree_view_range_changed,
4707 g_signal_connectc (tree_view->priv->model,
4709 (GCallback) gtk_tree_view_inserted,
4712 g_signal_connectc (tree_view->priv->model,
4713 "has_child_toggled",
4714 (GCallback) gtk_tree_view_has_child_toggled,
4717 g_signal_connectc (tree_view->priv->model,
4719 (GCallback) gtk_tree_view_deleted,
4722 g_signal_connectc (tree_view->priv->model,
4724 (GCallback) gtk_tree_view_reordered,
4728 if (tree_view->priv->columns == NULL)
4731 path = gtk_tree_path_new_root ();
4733 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
4735 tree_view->priv->tree = _gtk_rbtree_new ();
4736 gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
4739 gtk_tree_path_free (path);
4741 /* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
4743 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
4747 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
4752 GtkTreeViewColumn *column;
4754 gint max_height = 0;
4756 gint vertical_separator;
4760 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4761 /* do stuff with node */
4762 for (list = tree_view->priv->columns; list; list = list->next)
4764 gint height = 0, width = 0;
4765 column = list->data;
4767 if (!column->visible)
4770 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4776 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4778 gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4779 max_height = MAX (max_height, vertical_separator + height);
4781 if (i == tree_view->priv->expander_column &&
4782 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4783 _gtk_tree_view_column_set_width (column,
4784 MAX (column->width, depth * tree_view->priv->tab_offset + width));
4786 _gtk_tree_view_column_set_width (column,
4787 MAX (column->width, width));
4795 gtk_tree_view_build_tree (GtkTreeView *tree_view,
4800 gboolean calc_bounds)
4802 GtkRBNode *temp = NULL;
4809 max_height = gtk_tree_view_insert_iter_height (tree_view,
4814 gtk_tree_model_ref_node (tree_view->priv->model, iter);
4815 temp = _gtk_rbtree_insert_after (tree, temp, max_height);
4820 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4822 temp->children = _gtk_rbtree_new ();
4823 temp->children->parent_tree = tree;
4824 temp->children->parent_node = temp;
4825 gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
4828 if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
4830 if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
4831 temp->flags ^= GTK_RBNODE_IS_PARENT;
4832 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4835 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4839 gtk_tree_view_calc_size (GtkTreeView *tree_view,
4847 GtkTreeViewColumn *column;
4849 gint vertical_separator;
4852 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4854 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4857 while (temp->left != tree->nil)
4863 /* Do stuff with node */
4864 for (list = tree_view->priv->columns, i = 0; i < tree_view->priv->n_columns; list = list->next, i++)
4866 gint height = 0, width = 0;
4867 column = list->data;
4869 if (!column->visible)
4872 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4873 gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4874 max_height = MAX (max_height, vertical_separator + height);
4876 /* FIXME: I'm getting the width of all nodes here. )-: */
4877 if (column->dirty == FALSE)
4880 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4884 if (i == tree_view->priv->expander_column &&
4885 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4886 _gtk_tree_view_column_set_width (column,
4887 MAX (column->width, depth * tree_view->priv->tab_offset + width));
4889 _gtk_tree_view_column_set_width (column, MAX (column->width, width));
4892 _gtk_rbtree_node_set_height (tree, temp, max_height);
4894 if (temp->children != NULL &&
4895 gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4896 gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
4897 temp = _gtk_rbtree_next (tree, temp);
4899 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4903 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
4908 GtkTreeViewColumn *column;
4911 gboolean retval = FALSE;
4917 for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
4920 column = list->data;
4921 if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4923 if (!column->visible)
4926 gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4930 gtk_tree_view_column_cell_get_size (column,
4932 &width, &tmpheight);
4933 *height = MAX (*height, tmpheight);
4937 gtk_tree_view_column_cell_get_size (column,
4941 if (i == tree_view->priv->expander_column &&
4942 TREE_VIEW_DRAW_EXPANDERS (tree_view))
4944 if (depth * tree_view->priv->tab_offset + width > column->width)
4946 column->dirty = TRUE;
4952 if (width > column->width)
4954 column->dirty = TRUE;
4964 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
4969 GtkRBNode *temp = tree->root;
4970 GtkTreeViewColumn *column;
4973 gboolean is_all_dirty;
4975 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4977 while (temp->left != tree->nil)
4982 TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
4983 is_all_dirty = TRUE;
4984 for (list = tree_view->priv->columns; list; list = list->next)
4986 column = list->data;
4987 if (column->dirty == FALSE)
4989 is_all_dirty = FALSE;
4997 gtk_tree_view_discover_dirty_iter (tree_view,
5001 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
5002 temp->children != NULL)
5003 gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
5004 temp = _gtk_rbtree_next (tree, temp);
5006 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
5011 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
5014 gboolean dirty = FALSE;
5016 GtkTreeViewColumn *column;
5019 if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
5020 tree_view->priv->model)
5021 gtk_tree_view_setup_model (tree_view);
5023 for (list = tree_view->priv->columns; list; list = list->next)
5025 column = list->data;
5029 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5034 w = MAX (w, column->button->requisition.width);
5036 _gtk_tree_view_column_set_width (column, w);
5044 if (tree_view->priv->model == NULL)
5047 path = gtk_tree_path_new_root ();
5048 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
5050 gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
5051 _gtk_tree_view_update_size (tree_view);
5054 gtk_tree_path_free (path);
5056 for (list = tree_view->priv->columns; list; list = list->next)
5058 column = list->data;
5059 column->dirty = FALSE;
5063 /* Make sure the node is visible vertically */
5065 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
5071 /* We process updates because we want to clear old selected items when we scroll.
5072 * if this is removed, we get a "selection streak" at the bottom. */
5073 if (GTK_WIDGET_REALIZED (tree_view))
5074 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
5076 offset = _gtk_rbtree_node_find_offset (tree, node);
5078 /* we reverse the order, b/c in the unusual case of the
5079 * node's height being taller then the visible area, we'd rather
5080 * have the node flush to the top
5082 if (offset + GTK_RBNODE_GET_HEIGHT (node) >
5083 tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
5084 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5085 offset + GTK_RBNODE_GET_HEIGHT (node) -
5086 tree_view->priv->vadjustment->page_size);
5087 if (offset < tree_view->priv->vadjustment->value)
5088 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5093 /* This function could be more efficient.
5094 * I'll optimize it if profiling seems to imply that
5098 _gtk_tree_view_find_path (GtkTreeView *tree_view,
5103 GtkRBTree *tmp_tree;
5104 GtkRBNode *tmp_node, *last;
5107 path = gtk_tree_path_new ();
5109 g_return_val_if_fail (node != NULL, path);
5110 g_return_val_if_fail (node != tree->nil, path);
5112 count = 1 + node->left->count;
5115 tmp_node = node->parent;
5119 while (tmp_node != tmp_tree->nil)
5121 if (tmp_node->right == last)
5122 count += 1 + tmp_node->left->count;
5124 tmp_node = tmp_node->parent;
5126 gtk_tree_path_prepend_index (path, count - 1);
5127 last = tmp_tree->parent_node;
5128 tmp_tree = tmp_tree->parent_tree;
5131 count = 1 + last->left->count;
5132 tmp_node = last->parent;
5138 /* Returns TRUE if we ran out of tree before finding the path.
5141 _gtk_tree_view_find_node (GtkTreeView *tree_view,
5146 GtkRBNode *tmpnode = NULL;
5147 GtkRBTree *tmptree = tree_view->priv->tree;
5148 gint *indices = gtk_tree_path_get_indices (path);
5149 gint depth = gtk_tree_path_get_depth (path);
5159 if (tmptree == NULL)
5165 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5173 tmptree = tmpnode->children;
5179 gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
5182 GtkMovementStep step,
5186 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
5188 GTK_TYPE_ENUM, step,
5189 GTK_TYPE_INT, count);
5191 gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
5193 GTK_TYPE_ENUM, step,
5194 GTK_TYPE_INT, count);
5196 if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
5199 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
5201 GTK_TYPE_ENUM, step,
5202 GTK_TYPE_INT, count);
5204 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
5206 GTK_TYPE_ENUM, step,
5207 GTK_TYPE_INT, count);
5211 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
5218 g_return_if_fail (node != NULL);
5223 GtkRBTree *new_tree;
5224 GtkRBNode *new_node;
5226 new_tree = node->children;
5227 new_node = new_tree->root;
5229 while (new_node && new_node->left != new_tree->nil)
5230 new_node = new_node->left;
5232 g_return_if_fail (gtk_tree_model_iter_children (model, &child, iter));
5233 gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
5236 gtk_tree_model_unref_node (model, iter);
5237 node = _gtk_rbtree_next (tree, node);
5239 while (gtk_tree_model_iter_next (model, iter));
5243 gtk_tree_view_unref_tree (GtkTreeView *tree_view,
5251 while (node && node->left != tree->nil)
5254 g_return_if_fail (node != NULL);
5255 path = _gtk_tree_view_find_path (tree_view, tree, node);
5256 gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
5258 gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
5259 gtk_tree_path_free (path);
5263 gtk_tree_view_set_column_drag_info (GtkTreeView *tree_view,
5264 GtkTreeViewColumn *column)
5266 GtkTreeViewColumn *left_column;
5267 GtkTreeViewColumn *cur_column = NULL;
5268 GtkTreeViewColumnReorder *reorder;
5273 /* We want to precalculate the motion list such that we know what column slots
5278 /* First, identify all possible drop spots */
5279 tmp_list = tree_view->priv->columns;
5283 g_assert (tmp_list);
5285 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5286 tmp_list = tmp_list->next;
5288 if (cur_column->visible == FALSE)
5291 /* If it's not the column moving and func tells us to skip over the column, we continue. */
5292 if (left_column != column && cur_column != column &&
5293 tree_view->priv->column_drop_func &&
5294 ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5296 left_column = cur_column;
5299 reorder = g_new (GtkTreeViewColumnReorder, 1);
5300 reorder->left_column = left_column;
5301 left_column = reorder->right_column = cur_column;
5303 tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5306 /* Add the last one */
5307 if (tree_view->priv->column_drop_func == NULL ||
5308 ((left_column != column) &&
5309 (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
5311 reorder = g_new (GtkTreeViewColumnReorder, 1);
5312 reorder->left_column = left_column;
5313 reorder->right_column = NULL;
5314 tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5317 /* We quickly check to see if it even makes sense to reorder columns. */
5318 /* If there is nothing that can be moved, then we return */
5320 if (tree_view->priv->column_drag_info == NULL)
5323 /* We know there are always 2 slots possbile, as you can always return column. */
5324 /* If that's all there is, return */
5325 if (tree_view->priv->column_drag_info->next->next == NULL &&
5326 ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
5327 ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
5329 for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5330 g_free (tmp_list->data);
5331 g_list_free (tree_view->priv->column_drag_info);
5332 tree_view->priv->column_drag_info = NULL;
5335 /* We fill in the ranges for the columns, now that we've isolated them */
5336 left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5338 for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5340 reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
5342 reorder->left_align = left;
5343 if (tmp_list->next != NULL)
5345 g_assert (tmp_list->next->data);
5346 left = reorder->right_align = (reorder->right_column->button->allocation.x +
5347 reorder->right_column->button->allocation.width +
5348 ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
5354 gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
5355 reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5361 _gtk_tree_view_column_start_drag (GtkTreeView *tree_view,
5362 GtkTreeViewColumn *column)
5364 GdkEvent send_event;
5365 GtkAllocation allocation;
5366 gint x, y, width, height;
5368 g_return_if_fail (tree_view->priv->column_drag_info == NULL);
5370 gtk_tree_view_set_column_drag_info (tree_view, column);
5372 if (tree_view->priv->column_drag_info == NULL)
5375 if (tree_view->priv->drag_window == NULL)
5377 GdkWindowAttr attributes;
5378 guint attributes_mask;
5380 attributes.window_type = GDK_WINDOW_CHILD;
5381 attributes.wclass = GDK_INPUT_OUTPUT;
5382 attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
5383 attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
5384 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
5385 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
5387 tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
5390 gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
5393 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5394 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5396 gtk_grab_remove (column->button);
5398 send_event.crossing.type = GDK_LEAVE_NOTIFY;
5399 send_event.crossing.send_event = TRUE;
5400 send_event.crossing.window = column->button->window;
5401 send_event.crossing.subwindow = NULL;
5402 send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
5403 send_event.crossing.time = GDK_CURRENT_TIME;
5405 gtk_propagate_event (column->button, &send_event);
5407 send_event.button.type = GDK_BUTTON_RELEASE;
5408 send_event.button.window = GDK_ROOT_PARENT ();
5409 send_event.button.send_event = TRUE;
5410 send_event.button.time = GDK_CURRENT_TIME;
5411 send_event.button.x = -1;
5412 send_event.button.y = -1;
5413 send_event.button.axes = NULL;
5414 send_event.button.state = 0;
5415 send_event.button.button = 1;
5416 send_event.button.device = gdk_core_pointer;
5417 send_event.button.x_root = 0;
5418 send_event.button.y_root = 0;
5420 gtk_propagate_event (column->button, &send_event);
5422 gdk_window_move_resize (tree_view->priv->drag_window,
5423 column->button->allocation.x,
5424 column->button->allocation.y + column->button->allocation.height,
5425 column->button->allocation.width,
5426 column->button->allocation.height);
5427 gdk_window_reparent (column->button->window, tree_view->priv->drag_window, 0, 0);
5428 tree_view->priv->drag_column_x = column->button->allocation.x;
5429 allocation = column->button->allocation;
5431 gtk_widget_size_allocate (column->button, &allocation);
5432 gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
5434 tree_view->priv->drag_column = column;
5435 gdk_window_show (tree_view->priv->drag_window);
5437 gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
5438 gdk_window_get_size (tree_view->priv->header_window, &width, &height);
5440 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5441 while (gtk_events_pending ())
5442 gtk_main_iteration ();
5444 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
5445 gdk_pointer_grab (tree_view->priv->drag_window,
5447 GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
5448 NULL, NULL, GDK_CURRENT_TIME);
5449 gdk_keyboard_grab (tree_view->priv->drag_window,
5456 gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
5459 GdkRectangle *clip_rect)
5463 if (!GTK_WIDGET_REALIZED (tree_view))
5467 rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
5469 rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
5470 rect.height = BACKGROUND_HEIGHT (node);
5474 GdkRectangle new_rect;
5476 gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
5478 gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
5482 gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
5487 gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
5489 GdkRectangle *clip_rect)
5491 GtkRBTree *tree = NULL;
5492 GtkRBNode *node = NULL;
5494 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5497 gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
5500 /* x and y are the mouse position
5503 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
5513 gint vertical_separator;
5514 gint expander_height;
5516 gtk_widget_style_get (GTK_WIDGET (tree_view),
5517 "vertical_separator", &vertical_separator,
5518 "expander_height", &expander_height,
5521 if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
5524 widget = GTK_WIDGET (tree_view);
5526 gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
5529 area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
5530 area.width = tree_view->priv->tab_offset - 2;
5531 area.height = CELL_HEIGHT (node, vertical_separator);
5533 if (node == tree_view->priv->button_pressed_node)
5535 if (x >= area.x && x <= (area.x + area.width) &&
5536 y >= area.y && y <= (area.y + area.height))
5537 state = GTK_STATE_ACTIVE;
5539 state = GTK_STATE_NORMAL;
5543 if (node == tree_view->priv->prelight_node &&
5544 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
5545 state = GTK_STATE_PRELIGHT;
5547 state = GTK_STATE_NORMAL;
5550 gtk_paint_expander (widget->style,
5551 tree_view->priv->bin_window,
5557 (area.y + (area.height - expander_height) / 2 - (area.height + 1) % 2),
5558 node->children != NULL);
5563 _gtk_tree_view_update_col_width (GtkTreeView *tree_view)
5565 GList *list, *last_column;
5566 GtkTreeViewColumn *column;
5569 for (last_column = g_list_last (tree_view->priv->columns);
5571 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
5572 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
5573 last_column = last_column->prev)
5576 if (last_column == NULL)
5579 for (list = tree_view->priv->columns; list != last_column; list = list->next)
5581 column = GTK_TREE_VIEW_COLUMN (list->data);
5582 if (! column->visible)
5585 width += column->width;
5586 column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
5588 column = GTK_TREE_VIEW_COLUMN (last_column->data);
5589 column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
5593 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
5596 GtkTreePath *cursor_path;
5598 if ((tree_view->priv->tree == NULL) ||
5599 (! GTK_WIDGET_REALIZED (tree_view)))
5602 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
5603 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5606 if (tree_view->priv->cursor)
5607 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5609 if (cursor_path == NULL)
5611 GtkTreePath *tmp_path = gtk_tree_path_new_root ();
5612 /* FIXME: Get the first one visible!!! */
5613 if (tree_view->priv->cursor)
5614 gtk_tree_row_reference_free (tree_view->priv->cursor);
5616 tree_view->priv->cursor =
5617 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
5618 cursor_path = tmp_path;
5621 if (tree_view->priv->selection->type == GTK_TREE_SELECTION_SINGLE)
5622 gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, 0);
5624 gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, 0);
5625 gtk_tree_path_free (cursor_path);
5630 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
5633 GtkRBTree *cursor_tree = NULL;
5634 GtkRBNode *cursor_node = NULL;
5635 GtkRBTree *new_cursor_tree = NULL;
5636 GtkRBNode *new_cursor_node = NULL;
5637 GtkTreePath *cursor_path = NULL;
5640 if (tree_view->priv->cursor)
5641 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5643 if (cursor_path == NULL)
5646 _gtk_tree_view_find_node (tree_view, cursor_path,
5647 &cursor_tree, &cursor_node);
5650 _gtk_rbtree_prev_full (cursor_tree, cursor_node,
5651 &new_cursor_tree, &new_cursor_node);
5653 _gtk_rbtree_next_full (cursor_tree, cursor_node,
5654 &new_cursor_tree, &new_cursor_node);
5656 if (new_cursor_node)
5658 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5659 gtk_tree_path_free (cursor_path);
5661 cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
5662 if (!tree_view->priv->in_free_motion)
5663 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5667 tree_view->priv->in_extended_selection?GDK_SHIFT_MASK:0);
5668 gtk_tree_row_reference_free (tree_view->priv->cursor);
5669 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
5670 gtk_tree_view_clamp_node_visible (tree_view, new_cursor_tree, new_cursor_node);
5674 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5677 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5678 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5679 gtk_tree_path_free (cursor_path);
5683 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
5686 g_print ("gtk_tree_view_move_cursor_page_up_down\n");
5690 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
5693 GtkRBTree *cursor_tree = NULL;
5694 GtkRBNode *cursor_node = NULL;
5695 GtkTreePath *cursor_path = NULL;
5697 g_print ("gtk_tree_view_move_cursor_left_right\n");
5700 if (tree_view->priv->cursor)
5701 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5703 if (cursor_path == NULL)
5706 _gtk_tree_view_find_node (tree_view, cursor_path,
5707 &cursor_tree, &cursor_node);
5708 gtk_tree_path_free (cursor_path);
5714 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
5717 GtkRBTree *cursor_tree;
5718 GtkRBNode *cursor_node;
5721 g_return_if_fail (tree_view->priv->tree != NULL);
5725 cursor_tree = tree_view->priv->tree;
5726 cursor_node = cursor_tree->root;
5727 while (cursor_node && cursor_node->left != cursor_tree->nil)
5728 cursor_node = cursor_node->left;
5732 cursor_tree = tree_view->priv->tree;
5733 cursor_node = cursor_tree->root;
5736 while (cursor_node && cursor_node->right != cursor_tree->nil)
5737 cursor_node = cursor_node->right;
5738 if (cursor_node->children == NULL)
5741 cursor_tree = cursor_node->children;
5742 cursor_node = cursor_tree->root;
5747 path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5748 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5752 FALSE?GDK_SHIFT_MASK:0);
5754 gtk_tree_row_reference_free (tree_view->priv->cursor);
5755 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
5756 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5760 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view)
5762 GtkRBTree *cursor_tree = NULL;
5763 GtkRBNode *cursor_node = NULL;
5764 GtkTreePath *cursor_path = NULL;
5767 if (tree_view->priv->cursor)
5768 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5770 if (cursor_path == NULL)
5773 _gtk_tree_view_find_node (tree_view, cursor_path,
5774 &cursor_tree, &cursor_node);
5775 if (cursor_tree == NULL)
5778 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5784 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5786 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5787 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5788 gtk_tree_path_free (cursor_path);
5792 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
5794 GtkRBTree *cursor_tree = NULL;
5795 GtkRBNode *cursor_node = NULL;
5796 GtkTreePath *cursor_path = NULL;
5799 if (tree_view->priv->cursor)
5800 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5802 if (cursor_path == NULL)
5805 _gtk_tree_view_find_node (tree_view, cursor_path,
5806 &cursor_tree, &cursor_node);
5807 if (cursor_tree == NULL)
5810 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5816 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5818 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5819 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5820 gtk_tree_path_free (cursor_path);
5826 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
5831 GtkTreePath *cursor_path = NULL;
5834 if (tree_view->priv->cursor)
5835 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5837 if (cursor_path == NULL)
5841 gtk_tree_view_expand_row (tree_view, cursor_path, open_all);
5843 gtk_tree_view_collapse_row (tree_view, cursor_path);
5845 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5846 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5847 gtk_tree_path_free (cursor_path);
5851 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
5853 GtkRBTree *cursor_tree = NULL;
5854 GtkRBNode *cursor_node = NULL;
5855 GtkTreePath *cursor_path = NULL;
5858 if (tree_view->priv->cursor)
5859 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5861 if (cursor_path == NULL)
5864 _gtk_tree_view_find_node (tree_view, cursor_path,
5865 &cursor_tree, &cursor_node);
5866 if (cursor_tree == NULL)
5869 if (cursor_tree->parent_node)
5871 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5872 cursor_node = cursor_tree->parent_node;
5873 cursor_tree = cursor_tree->parent_tree;
5875 gtk_tree_path_up (cursor_path);
5876 gtk_tree_row_reference_free (tree_view->priv->cursor);
5877 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
5878 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5885 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5887 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5888 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5889 gtk_tree_path_free (cursor_path);
5893 _gtk_tree_view_update_size (GtkTreeView *tree_view)
5897 GtkTreeViewColumn *column;
5898 gint vertical_separator;
5901 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5903 if (tree_view->priv->model == NULL)
5905 tree_view->priv->width = 0;
5906 tree_view->priv->height = 0;
5907 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5912 for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
5914 column = list->data;
5915 if (!column->visible)
5917 width += TREE_VIEW_COLUMN_WIDTH (column);
5920 if (tree_view->priv->tree == NULL)
5923 height = tree_view->priv->tree->root->offset + vertical_separator;
5925 if (tree_view->priv->width != width)
5927 tree_view->priv->width = width;
5928 tree_view->priv->hadjustment->upper = width;
5929 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
5932 if (tree_view->priv->height != height)
5934 tree_view->priv->height = height;
5935 tree_view->priv->vadjustment->upper = tree_view->priv->height;
5936 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
5939 if (GTK_WIDGET_REALIZED (tree_view))
5941 gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
5942 gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
5944 _gtk_tree_view_update_col_width (tree_view);
5947 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5950 /* this function returns the new width of the column being resized given
5951 * the column and x position of the cursor; the x cursor position is passed
5952 * in as a pointer and automagicly corrected if it's beyond min/max limits
5955 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
5959 GtkTreeViewColumn *column;
5962 /* first translate the x position from widget->window
5963 * to clist->clist_window
5966 column = g_list_nth (tree_view->priv->columns, i)->data;
5967 width = *x - column->button->allocation.x;
5969 /* Clamp down the value */
5970 if (column->min_width == -1)
5971 width = MAX (column->button->requisition.width,
5974 width = MAX (column->min_width,
5976 if (column->max_width != -1)
5977 width = MIN (width, column->max_width != -1);
5978 *x = column->button->allocation.x + width;
5986 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
5987 GtkTreeView *tree_view)
5989 if (GTK_WIDGET_REALIZED (tree_view))
5991 gdk_window_move (tree_view->priv->bin_window,
5992 - tree_view->priv->hadjustment->value,
5993 - tree_view->priv->vadjustment->value);
5994 gdk_window_move (tree_view->priv->header_window,
5995 - tree_view->priv->hadjustment->value,
5998 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
5999 gdk_window_process_updates (tree_view->priv->header_window, TRUE);
6009 * gtk_tree_view_new:
6011 * Creates a new #GtkTreeView widget.
6013 * Return value: A newly created #GtkTreeView widget.
6016 gtk_tree_view_new (void)
6018 GtkTreeView *tree_view;
6020 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6022 return GTK_WIDGET (tree_view);
6026 * gtk_tree_view_new_with_model:
6027 * @model: the model.
6029 * Creates a new #GtkTreeView widget with the model initialized to @model.
6031 * Return value: A newly created #GtkTreeView widget.
6034 gtk_tree_view_new_with_model (GtkTreeModel *model)
6036 GtkTreeView *tree_view;
6038 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6039 gtk_tree_view_set_model (tree_view, model);
6041 return GTK_WIDGET (tree_view);
6048 * gtk_tree_view_get_model:
6049 * @tree_view: a #GtkTreeView
6051 * Returns the model the the #GtkTreeView is based on. Returns NULL if the
6054 * Return value: A #GtkTreeModel, or NULL if none is currently being used.
6057 gtk_tree_view_get_model (GtkTreeView *tree_view)
6059 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6061 return tree_view->priv->model;
6065 * gtk_tree_view_set_model:
6066 * @tree_view: A #GtkTreeNode.
6067 * @model: The model.
6069 * Sets the model for a #GtkTreeView. If the @tree_view already has a model
6070 * set, it will remove it before setting the new model. If @model is NULL, then
6071 * it will unset the old model.
6074 gtk_tree_view_set_model (GtkTreeView *tree_view,
6075 GtkTreeModel *model)
6077 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6079 if (model == tree_view->priv->model)
6083 g_object_ref (model);
6085 if (tree_view->priv->model != NULL)
6087 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
6089 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6090 G_SIGNAL_MATCH_DATA,
6093 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6094 G_SIGNAL_MATCH_DATA,
6097 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6098 G_SIGNAL_MATCH_DATA,
6101 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6102 G_SIGNAL_MATCH_DATA,
6105 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6106 G_SIGNAL_MATCH_DATA,
6109 if (tree_view->priv->tree)
6110 _gtk_rbtree_free (tree_view->priv->tree);
6113 if (tree_view->priv->drag_dest_row)
6114 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
6116 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
6117 g_object_unref (tree_view->priv->model);
6120 tree_view->priv->model = model;
6124 tree_view->priv->tree = NULL;
6125 if (GTK_WIDGET_REALIZED (tree_view))
6126 _gtk_tree_view_update_size (tree_view);
6128 else if (GTK_WIDGET_REALIZED (tree_view))
6130 gtk_tree_view_setup_model (tree_view);
6131 _gtk_tree_view_update_size (tree_view);
6134 g_object_notify (G_OBJECT (tree_view), "model");
6138 * gtk_tree_view_get_selection:
6139 * @tree_view: A #GtkTreeView.
6141 * Gets the #GtkTreeSelection associated with @tree_view.
6143 * Return value: A #GtkTreeSelection object.
6146 gtk_tree_view_get_selection (GtkTreeView *tree_view)
6148 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6150 return tree_view->priv->selection;
6154 * gtk_tree_view_get_hadjustment:
6155 * @tree_view: A #GtkTreeView
6157 * Gets the #GtkAdjustment currently being used for the horizontal aspect.
6159 * Return value: A #GtkAdjustment object, or NULL if none is currently being
6163 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
6165 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6167 if (tree_view->priv->hadjustment == NULL)
6168 gtk_tree_view_set_hadjustment (tree_view, NULL);
6170 return tree_view->priv->hadjustment;
6174 * gtk_tree_view_set_hadjustment:
6175 * @tree_view: A #GtkTreeView
6176 * @adjustment: The #GtkAdjustment to set, or NULL
6178 * Sets the #GtkAdjustment for the current horizontal aspect.
6181 gtk_tree_view_set_hadjustment (GtkTreeView *tree_view,
6182 GtkAdjustment *adjustment)
6184 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6186 gtk_tree_view_set_adjustments (tree_view,
6188 tree_view->priv->vadjustment);
6190 g_object_notify (G_OBJECT (tree_view), "hadjustment");
6194 * gtk_tree_view_get_vadjustment:
6195 * @tree_view: A #GtkTreeView
6197 * Gets the #GtkAdjustment currently being used for the vertical aspect.
6199 * Return value: A #GtkAdjustment object, or NULL if none is currently being
6203 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
6205 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6207 if (tree_view->priv->vadjustment == NULL)
6208 gtk_tree_view_set_vadjustment (tree_view, NULL);
6210 return tree_view->priv->vadjustment;
6214 * gtk_tree_view_set_vadjustment:
6215 * @tree_view: A #GtkTreeView
6216 * @adjustment: The #GtkAdjustment to set, or NULL
6218 * Sets the #GtkAdjustment for the current vertical aspect.
6221 gtk_tree_view_set_vadjustment (GtkTreeView *tree_view,
6222 GtkAdjustment *adjustment)
6224 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6226 gtk_tree_view_set_adjustments (tree_view,
6227 tree_view->priv->hadjustment,
6230 g_object_notify (G_OBJECT (tree_view), "vadjustment");
6233 /* Column and header operations */
6236 * gtk_tree_view_get_headers_visible:
6237 * @tree_view: A #GtkTreeView.
6239 * Returns TRUE if the headers on the @tree_view are visible.
6241 * Return value: Whether the headers are visible or not.
6244 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
6246 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6248 return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6252 * gtk_tree_view_set_headers_visible:
6253 * @tree_view: A #GtkTreeView.
6254 * @headers_visible: TRUE if the headers are visible
6256 * Sets the the visibility state of the headers.
6259 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
6260 gboolean headers_visible)
6264 GtkTreeViewColumn *column;
6266 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6268 headers_visible = !! headers_visible;
6270 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
6273 if (headers_visible)
6274 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6276 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6278 if (GTK_WIDGET_REALIZED (tree_view))
6280 gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
6281 if (headers_visible)
6283 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));
6285 if (GTK_WIDGET_MAPPED (tree_view))
6286 gtk_tree_view_map_buttons (tree_view);
6290 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
6292 for (list = tree_view->priv->columns; list; list = list->next)
6294 column = list->data;
6295 gtk_widget_unmap (column->button);
6297 gdk_window_hide (tree_view->priv->header_window);
6301 tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
6302 tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
6303 tree_view->priv->vadjustment->lower = 0;
6304 tree_view->priv->vadjustment->upper = tree_view->priv->height;
6305 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
6307 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6309 g_object_notify (G_OBJECT (tree_view), "headers_visible");
6314 * gtk_tree_view_columns_autosize:
6315 * @tree_view: A #GtkTreeView.
6317 * Resizes all columns to their optimal width.
6320 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
6322 gboolean dirty = FALSE;
6324 GtkTreeViewColumn *column;
6326 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6328 for (list = tree_view->priv->columns; list; list = list->next)
6330 column = list->data;
6331 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
6333 column->dirty = TRUE;
6338 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6342 * gtk_tree_view_set_headers_clickable:
6343 * @tree_view: A #GtkTreeView.
6344 * @setting: TRUE if the columns are clickable.
6346 * Allow the column title buttons to be clicked.
6349 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
6354 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6355 g_return_if_fail (tree_view->priv->model != NULL);
6357 for (list = tree_view->priv->columns; list; list = list->next)
6358 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
6360 g_object_notify (G_OBJECT (tree_view), "headers_clickable");
6365 * gtk_tree_view_set_rules_hint
6366 * @tree_view: a #GtkTreeView
6367 * @setting: %TRUE if the tree requires reading across rows
6369 * This function tells GTK+ that the user interface for your
6370 * application requires users to read across tree rows and associate
6371 * cells with one another. By default, GTK+ will then render the tree
6372 * with alternating row colors. <emphasis>DO NOT</emphasis> use it
6373 * just because you prefer the appearance of the ruled tree; that's a
6374 * question for the theme. Some themes will draw tree rows in
6375 * alternating colors even when rules are turned off, and users who
6376 * prefer that appearance all the time can choose those themes. You
6377 * should call this function only as a <emphasis>semantic</emphasis>
6378 * hint to the theme engine that your tree makes alternating colors
6379 * useful from a functional standpoint (since it has lots of columns,
6384 gtk_tree_view_set_rules_hint (GtkTreeView *tree_view,
6387 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6389 setting = setting != FALSE;
6391 if (tree_view->priv->has_rules != setting)
6393 tree_view->priv->has_rules = setting;
6394 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6397 g_object_notify (G_OBJECT (tree_view), "rules_hint");
6401 * gtk_tree_view_get_rules_hint
6402 * @tree_view: a #GtkTreeView
6404 * Gets the setting set by gtk_tree_view_set_rules_hint().
6406 * Return value: %TRUE if rules are useful for the user of this tree
6409 gtk_tree_view_get_rules_hint (GtkTreeView *tree_view)
6411 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6413 return tree_view->priv->has_rules;
6416 /* Public Column functions
6420 * gtk_tree_view_append_column:
6421 * @tree_view: A #GtkTreeView.
6422 * @column: The #GtkTreeViewColumn to add.
6424 * Appends @column to the list of columns.
6426 * Return value: The number of columns in @tree_view after appending.
6429 gtk_tree_view_append_column (GtkTreeView *tree_view,
6430 GtkTreeViewColumn *column)
6432 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6433 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6434 g_return_val_if_fail (column->tree_view == NULL, -1);
6436 return gtk_tree_view_insert_column (tree_view, column, -1);
6441 * gtk_tree_view_remove_column:
6442 * @tree_view: A #GtkTreeView.
6443 * @column: The #GtkTreeViewColumn to remove.
6445 * Removes @column from @tree_view.
6447 * Return value: The number of columns in @tree_view after removing.
6450 gtk_tree_view_remove_column (GtkTreeView *tree_view,
6451 GtkTreeViewColumn *column)
6453 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6454 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6455 g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
6457 _gtk_tree_view_column_unset_tree_view (column);
6459 if (tree_view->priv->focus_column == column)
6460 tree_view->priv->focus_column = NULL;
6462 tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
6464 tree_view->priv->n_columns--;
6466 if (GTK_WIDGET_REALIZED (tree_view))
6470 _gtk_tree_view_column_unrealize_button (column);
6471 for (list = tree_view->priv->columns; list; list = list->next)
6473 column = GTK_TREE_VIEW_COLUMN (list->data);
6474 if (column->visible)
6475 column->dirty = TRUE;
6478 if (tree_view->priv->n_columns == 0 &&
6479 gtk_tree_view_get_headers_visible (tree_view))
6480 gdk_window_hide (tree_view->priv->header_window);
6482 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6485 g_object_unref (G_OBJECT (column));
6486 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6488 return tree_view->priv->n_columns;
6492 * gtk_tree_view_insert_column:
6493 * @tree_view: A #GtkTreeView.
6494 * @column: The #GtkTreeViewColumn to be inserted.
6495 * @position: The position to insert @column in.
6497 * This inserts the @column into the @tree_view at @position. If @position is
6498 * -1, then the column is inserted at the end.
6500 * Return value: The number of columns in @tree_view after insertion.
6503 gtk_tree_view_insert_column (GtkTreeView *tree_view,
6504 GtkTreeViewColumn *column,
6507 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6508 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6509 g_return_val_if_fail (column->tree_view == NULL, -1);
6511 g_object_ref (G_OBJECT (column));
6513 if (tree_view->priv->n_columns == 0 &&
6514 GTK_WIDGET_REALIZED (tree_view) &&
6515 gtk_tree_view_get_headers_visible (tree_view))
6517 gdk_window_show (tree_view->priv->header_window);
6520 tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
6522 tree_view->priv->n_columns++;
6524 _gtk_tree_view_column_set_tree_view (column, tree_view);
6526 if (GTK_WIDGET_REALIZED (tree_view))
6530 _gtk_tree_view_column_realize_button (column);
6532 for (list = tree_view->priv->columns; list; list = list->next)
6534 column = GTK_TREE_VIEW_COLUMN (list->data);
6535 if (column->visible)
6536 column->dirty = TRUE;
6538 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6541 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6543 return tree_view->priv->n_columns;
6547 * gtk_tree_view_insert_column_with_attributes:
6548 * @tree_view: A #GtkTreeView
6549 * @position: The position to insert the new column in.
6550 * @title: The title to set the header to.
6551 * @cell: The #GtkCellRenderer.
6552 * @Varargs: A NULL terminated list of attributes.
6554 * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
6555 * @position. If @position is -1, then the newly created column is inserted at
6556 * the end. The column is initialized with the attributes given.
6558 * Return value: The number of columns in @tree_view after insertion.
6561 gtk_tree_view_insert_column_with_attributes (GtkTreeView *tree_view,
6564 GtkCellRenderer *cell,
6567 GtkTreeViewColumn *column;
6572 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6574 column = gtk_tree_view_column_new ();
6576 gtk_tree_view_column_set_title (column, title);
6577 gtk_tree_view_column_set_cell_renderer (column, cell);
6579 va_start (args, cell);
6581 attribute = va_arg (args, gchar *);
6583 while (attribute != NULL)
6585 column_id = va_arg (args, gint);
6586 gtk_tree_view_column_add_attribute (column, attribute, column_id);
6587 attribute = va_arg (args, gchar *);
6592 gtk_tree_view_insert_column (tree_view, column, position);
6593 g_object_unref (column);
6595 return tree_view->priv->n_columns;
6599 * gtk_tree_view_insert_column_with_data_func:
6600 * @tree_view: a #GtkTreeView
6601 * @position: Position to insert, -1 for append
6602 * @title: column title
6603 * @cell: cell renderer for column
6604 * @func: function to set attributes of cell renderer
6605 * @data: data for @func
6606 * @dnotify: destroy notifier for @data
6608 * Convenience function that inserts a new column into the #GtkTreeView
6609 * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
6610 * attributes (normally using data from the model). See also
6611 * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_set_cell_renderer().
6613 * Return value: number of columns in the tree view post-insert
6616 gtk_tree_view_insert_column_with_data_func (GtkTreeView *tree_view,
6619 GtkCellRenderer *cell,
6620 GtkTreeCellDataFunc func,
6622 GDestroyNotify dnotify)
6624 GtkTreeViewColumn *column;
6626 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6628 column = gtk_tree_view_column_new ();
6630 gtk_tree_view_column_set_title (column, title);
6631 gtk_tree_view_column_set_cell_renderer (column, cell);
6632 gtk_tree_view_column_set_cell_data_func (column, func, data, dnotify);
6634 gtk_tree_view_insert_column (tree_view, column, position);
6636 g_object_unref (column);
6638 return tree_view->priv->n_columns;
6642 * gtk_tree_view_get_column:
6643 * @tree_view: A #GtkTreeView.
6644 * @n: The position of the column, counting from 0.
6646 * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
6648 * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
6652 gtk_tree_view_get_column (GtkTreeView *tree_view,
6655 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6657 if (n < 0 || n >= tree_view->priv->n_columns)
6660 if (tree_view->priv->columns == NULL)
6663 return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
6667 * gtk_tree_view_get_columns:
6668 * @tree_view: A #GtkTreeView
6670 * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
6671 * The returned list must be freed with g_list_free ().
6673 * Return value: A list of #GtkTreeViewColumn s
6676 gtk_tree_view_get_columns (GtkTreeView *tree_view)
6678 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6680 return g_list_copy (tree_view->priv->columns);
6684 * gtk_tree_view_move_column_after:
6685 * @tree_view: A #GtkTreeView
6686 * @column: The #GtkTreeViewColumn to be moved.
6687 * @base_column: The #GtkTreeViewColumn to be moved relative to.
6689 * Moves @column to be after to @base_column. If @base_column is NULL, then
6690 * @column is placed in the first position.
6693 gtk_tree_view_move_column_after (GtkTreeView *tree_view,
6694 GtkTreeViewColumn *column,
6695 GtkTreeViewColumn *base_column)
6697 GList *column_list_el, *base_el = NULL;
6699 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6701 column_list_el = g_list_find (tree_view->priv->columns, column);
6702 g_return_if_fail (column_list_el != NULL);
6706 base_el = g_list_find (tree_view->priv->columns, base_column);
6707 g_return_if_fail (base_el != NULL);
6710 if (column_list_el->prev == base_el)
6713 tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
6714 if (base_el == NULL)
6716 column_list_el->prev = NULL;
6717 column_list_el->next = tree_view->priv->columns;
6718 if (column_list_el->next)
6719 column_list_el->next->prev = column_list_el;
6720 tree_view->priv->columns = column_list_el;
6724 column_list_el->prev = base_el;
6725 column_list_el->next = base_el->next;
6726 if (column_list_el->next)
6727 column_list_el->next->prev = column_list_el;
6728 base_el->next = column_list_el;
6731 if (GTK_WIDGET_REALIZED (tree_view))
6733 //gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6734 _gtk_tree_view_update_size (tree_view);
6735 gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view));
6738 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6742 * gtk_tree_view_set_expander_column:
6743 * @tree_view: A #GtkTreeView
6744 * @col: The column to draw the expander arrow at.
6746 * Sets the column offset to draw the expander arrow at.
6749 gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
6752 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6754 if (tree_view->priv->expander_column != col)
6756 tree_view->priv->expander_column = col;
6758 g_object_notify (G_OBJECT (tree_view), "expander_column");
6763 * gtk_tree_view_get_expander_column:
6766 * Returns the offset of the column that is the current expander column. This
6767 * column has the expander arrow drawn next to it.
6769 * Return value: The offset of the expander column.
6772 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
6774 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6776 return tree_view->priv->expander_column;
6781 * gtk_tree_view_set_column_drag_function:
6782 * @tree_view: A #GtkTreeView.
6783 * @func: A function to determine which columns are reorderable, or NULL.
6784 * @user_data: User data to be passed to @func, or NULL
6785 * @destroy: Destroy notifier for @user_data, or NULL
6787 * Sets a user function for determining where a column may be dropped when
6788 * dragged. This function is called on every column pair in turn at the
6789 * beginning of a column drag to determine where a drop can take place. The
6790 * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
6791 * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
6792 * @user_data. If either of the #GtkTreeViewColumn arguments for the drop spot
6793 * are NULL, then they indicate an edge. If @func is set to be NULL, then
6794 * @tree_view reverts to the default behavior of allowing all columns to be
6795 * dropped everywhere.
6798 gtk_tree_view_set_column_drag_function (GtkTreeView *tree_view,
6799 GtkTreeViewColumnDropFunc func,
6801 GtkDestroyNotify destroy)
6803 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6805 if (tree_view->priv->column_drop_func_data_destroy)
6806 (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
6808 tree_view->priv->column_drop_func = func;
6809 tree_view->priv->column_drop_func_data = user_data;
6810 tree_view->priv->column_drop_func_data_destroy = destroy;
6814 * gtk_tree_view_scroll_to_point:
6815 * @tree_view: a #GtkTreeView
6816 * @tree_x: X coordinate of new top-left pixel of visible area
6817 * @tree_y: Y coordinate of new top-left pixel of visible area
6819 * Scrolls the tree view such that the top-left corner of the visible
6820 * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
6821 * in tree window coordinates. The @tree_view must be realized before
6822 * this function is called. If it isn't, you probably want ot be
6823 * using gtk_tree_view_scroll_to_cell.
6826 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
6830 GtkAdjustment *hadj;
6831 GtkAdjustment *vadj;
6833 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6834 g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
6836 hadj = tree_view->priv->hadjustment;
6837 vadj = tree_view->priv->vadjustment;
6839 gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
6840 gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
6844 * gtk_tree_view_scroll_to_cell
6845 * @tree_view: A #GtkTreeView.
6846 * @path: The path of the row to move to.
6847 * @column: The #GtkTreeViewColumn to move horizontally to.
6848 * @row_align: The vertical alignment of the row specified by @path.
6849 * @col_align: The horizontal alignment of the column specified by @column.
6851 * Moves the alignments of @tree_view to the position specified by
6852 * @column and @path. If @column is NULL, then no horizontal
6853 * scrolling occurs. Likewise, if @path is NULL no vertical scrolling
6854 * occurs. @row_align determines where the row is placed, and
6855 * @col_align determines where @column is placed. Both are expected
6856 * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
6857 * right/bottom alignment, 0.5 means center.
6860 gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
6862 GtkTreeViewColumn *column,
6866 GdkRectangle cell_rect;
6867 GdkRectangle vis_rect;
6868 gint dest_x, dest_y;
6870 /* FIXME work on unmapped/unrealized trees? maybe implement when
6871 * we do incremental reflow for trees
6874 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6875 g_return_if_fail (row_align >= 0.0);
6876 g_return_if_fail (row_align <= 1.0);
6877 g_return_if_fail (col_align >= 0.0);
6878 g_return_if_fail (col_align <= 1.0);
6879 g_return_if_fail (path != NULL || column != NULL);
6881 row_align = CLAMP (row_align, 0.0, 1.0);
6882 col_align = CLAMP (col_align, 0.0, 1.0);
6884 if (! GTK_WIDGET_REALIZED (tree_view))
6887 tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
6889 tree_view->priv->scroll_to_column = column;
6890 tree_view->priv->scroll_to_row_align = row_align;
6891 tree_view->priv->scroll_to_col_align = col_align;
6896 gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
6897 gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
6899 dest_x = vis_rect.x;
6900 dest_y = vis_rect.y;
6904 dest_x = cell_rect.x +
6905 cell_rect.width * row_align -
6906 vis_rect.width * row_align;
6911 dest_y = cell_rect.y +
6912 cell_rect.height * col_align -
6913 vis_rect.height * col_align;
6916 gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
6921 * gtk_tree_view_row_activated:
6922 * @tree_view: A #GtkTreeView
6923 * @path: The #GtkTreePath to be activated.
6924 * @column: The #GtkTreeViewColumn to be activated.
6926 * Activates the cell determined by @path and @column.
6929 gtk_tree_view_row_activated (GtkTreeView *tree_view,
6931 GtkTreeViewColumn *column)
6933 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6935 /* FIXME: Actually activate the path internally, not just emit the signal */
6936 /* g_warning ("FIXME: Actually activate the path internally, not just emit the signal\n"); */
6937 g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
6942 gtk_tree_view_expand_all_helper (GtkRBTree *tree,
6946 GtkTreeView *tree_view = data;
6949 _gtk_rbtree_traverse (node->children,
6950 node->children->root,
6952 gtk_tree_view_expand_all_helper,
6954 else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
6960 node->children = _gtk_rbtree_new ();
6961 node->children->parent_tree = tree;
6962 node->children->parent_node = node;
6963 path = _gtk_tree_view_find_path (tree_view, tree, node);
6964 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6965 gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
6966 gtk_tree_view_build_tree (tree_view,
6969 gtk_tree_path_get_depth (path) + 1,
6971 GTK_WIDGET_REALIZED (tree_view));
6972 gtk_tree_path_free (path);
6977 * gtk_tree_view_expand_all:
6978 * @tree_view: A #GtkTreeView.
6980 * Recursively expands all nodes in the @tree_view.
6983 gtk_tree_view_expand_all (GtkTreeView *tree_view)
6985 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6986 g_return_if_fail (tree_view->priv->tree != NULL);
6988 _gtk_rbtree_traverse (tree_view->priv->tree,
6989 tree_view->priv->tree->root,
6991 gtk_tree_view_expand_all_helper,
6994 _gtk_tree_view_update_size (tree_view);
6998 gtk_tree_view_collapse_all_helper (GtkRBTree *tree,
7007 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
7009 node->children->root);
7010 gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
7013 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
7016 gtk_tree_path_get_depth (path));
7018 /* Ensure we don't have a dangling pointer to a dead node */
7019 ensure_unprelighted (GTK_TREE_VIEW (data));
7021 _gtk_rbtree_remove (node->children);
7022 gtk_tree_path_free (path);
7027 * gtk_tree_view_collapse_all:
7028 * @tree_view: A #GtkTreeView.
7030 * Recursively collapses all visible, expanded nodes in @tree_view.
7033 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
7035 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7036 g_return_if_fail (tree_view->priv->tree != NULL);
7038 _gtk_rbtree_traverse (tree_view->priv->tree,
7039 tree_view->priv->tree->root,
7041 gtk_tree_view_collapse_all_helper,
7044 if (GTK_WIDGET_MAPPED (tree_view))
7045 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7048 /* FIXME the bool return values for expand_row and collapse_row are
7049 * not analagous; they should be TRUE if the row had children and
7050 * was not already in the requested state.
7055 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
7068 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7069 if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
7072 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
7077 node->children = _gtk_rbtree_new ();
7078 node->children->parent_tree = tree;
7079 node->children->parent_node = node;
7081 gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
7082 gtk_tree_view_build_tree (tree_view,
7085 gtk_tree_path_get_depth (path) + 1,
7087 GTK_WIDGET_REALIZED (tree_view));
7089 if (GTK_WIDGET_MAPPED (tree_view))
7091 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7092 _gtk_tree_view_update_size (tree_view);
7095 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
7102 * gtk_tree_view_expand_row:
7103 * @tree_view: a #GtkTreeView
7104 * @path: path to a row
7105 * @open_all: whether to recursively expand, or just expand immediate children
7107 * Opens the row so its children are visible
7109 * Return value: %TRUE if the row existed and had children
7112 gtk_tree_view_expand_row (GtkTreeView *tree_view,
7119 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7120 g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
7121 g_return_val_if_fail (path != NULL, FALSE);
7123 if (_gtk_tree_view_find_node (tree_view,
7129 return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all);
7133 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
7141 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7143 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
7148 TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model,
7152 gtk_tree_view_discover_dirty (tree_view,
7155 gtk_tree_path_get_depth (path));
7157 /* Ensure we don't have a dangling pointer to a dead node */
7158 ensure_unprelighted (tree_view);
7160 g_assert (tree_view->priv->prelight_node == NULL);
7162 gtk_tree_view_unref_tree (tree_view, node->children);
7163 _gtk_rbtree_remove (node->children);
7165 if (GTK_WIDGET_MAPPED (tree_view))
7167 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7168 _gtk_tree_view_update_size (tree_view);
7171 g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
7177 * gtk_tree_view_collapse_row:
7178 * @tree_view: a #GtkTreeView
7179 * @path: path to a row in the @tree_view
7181 * Collapses a row (hides its child rows, if they exist.)
7183 * Return value: %TRUE if the row was collapsed.
7186 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
7192 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7193 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7194 g_return_val_if_fail (path != NULL, FALSE);
7196 if (_gtk_tree_view_find_node (tree_view,
7202 if (node->children == NULL)
7205 return gtk_tree_view_real_collapse_row (tree_view, path, tree, node);
7209 gtk_tree_view_map_expanded_rows_helper (GtkTreeView *tree_view,
7212 GtkTreeViewMappingFunc func,
7220 if (tree == NULL || tree->root == NULL)
7225 indices = gtk_tree_path_get_indices (path);
7226 depth = gtk_tree_path_get_depth (path);
7228 while (node && node->left != tree->nil)
7235 gtk_tree_path_append_index (path, 0);
7236 gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
7237 gtk_tree_path_up (path);
7238 (* func) (tree_view, path, user_data);
7241 indices[depth -1] = i;
7242 node = _gtk_rbtree_next (tree, node);
7247 * gtk_tree_view_map_expanded_rows:
7248 * @tree_view: A #GtkTreeView
7249 * @func: A function to be called
7250 * @data: User data to be passed to the function.
7252 * Calls @func on all expanded rows.
7255 gtk_tree_view_map_expanded_rows (GtkTreeView *tree_view,
7256 GtkTreeViewMappingFunc func,
7261 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7262 g_return_if_fail (func != NULL);
7264 path = gtk_tree_path_new_root ();
7266 gtk_tree_view_map_expanded_rows_helper (tree_view,
7267 tree_view->priv->tree,
7268 path, func, user_data);
7270 gtk_tree_path_free (path);
7273 static GtkTargetEntry row_targets[] = {
7274 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7278 * gtk_tree_view_set_reorderable:
7279 * @tree_view: A #GtkTreeView.
7280 * @reorderable: TRUE, if the tree can be reordered.
7282 * This function is a convenience function to allow you to reorder models that
7283 * support the #GtkDragSourceIface and the #GtkDragDestIface. Both
7284 * #GtkTreeStore and #GtkListStore support these. If @reorderable is TRUE, then
7285 * the user can reorder the model by dragging and dropping columns. The
7286 * developer will can listen to these changes by connecting to the model's
7289 * This function does not give you any degree of control over the order -- any
7290 * reorderering is allowed. If more control is needed, you should probably
7291 * handle drag and drop manually.
7294 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
7295 gboolean reorderable)
7297 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7299 if (tree_view->priv->reorderable == (reorderable?TRUE:FALSE))
7302 gtk_tree_view_set_rows_drag_source (tree_view,
7305 G_N_ELEMENTS (row_targets),
7308 gtk_tree_view_set_rows_drag_dest (tree_view,
7310 G_N_ELEMENTS (row_targets),
7314 g_object_notify (G_OBJECT (tree_view), "reorderable");
7318 gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
7320 gboolean clear_and_select,
7321 GdkModifierType state)
7323 GtkRBTree *tree = NULL;
7324 GtkRBNode *node = NULL;
7326 if (tree_view->priv->cursor)
7327 gtk_tree_row_reference_free (tree_view->priv->cursor);
7328 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7329 tree_view->priv->model,
7331 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7335 if (clear_and_select)
7337 gtk_tree_selection_unselect_all (tree_view->priv->selection);
7338 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7342 gtk_tree_view_clamp_node_visible (tree_view, tree, node);
7343 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
7347 * gtk_tree_view_set_cursor:
7348 * @tree_view: A #GtkTreeView
7349 * @path: A #GtkTreePath
7351 * Sets the current keyboard focus to be at @path, and selects it. This is
7352 * useful when you want to focus the user's attention on a particular row. If
7353 * you want to give the user keyboard focus in the tree_view, you should use
7354 * this function to set the correct path, and gtk_widget_grab_focus (GTK_WIDGET
7355 * (tree_view)) to actually give focus to the @tree_view.
7358 gtk_tree_view_set_cursor (GtkTreeView *tree_view,
7361 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7362 g_return_if_fail (path != NULL);
7364 gtk_tree_view_real_set_cursor (tree_view, path, TRUE, 0);
7369 * gtk_tree_view_get_path_at_pos:
7370 * @tree_view: A #GtkTreeView.
7371 * @window: The #GdkWindow to check against.
7372 * @x: The x position to be identified.
7373 * @y: The y position to be identified.
7374 * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
7375 * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
7376 * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
7377 * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
7379 * Finds the path at the point (@x, @y) relative to @window. If @window is
7380 * NULL, then the point is found relative to the widget coordinates. This
7381 * function is expected to be called after an event, with event->window being
7382 * passed in as @window. It is primarily for things like popup menus. If @path
7383 * is non-NULL, then it will be filled with the #GtkTreePath at that point.
7384 * This path should be freed with #gtk_tree_path_free. If @column is non-NULL,
7385 * then it will be filled with the column at that point. @cell_x and @cell_y
7386 * return the coordinates relative to the cell background (i.e. the
7387 * background_area passed to gtk_cell_renderer_render()). This function only
7388 * works if @tree_view is realized.
7390 * Return value: TRUE if a row exists at that coordinate.
7393 gtk_tree_view_get_path_at_pos (GtkTreeView *tree_view,
7398 GtkTreeViewColumn **column,
7406 g_return_val_if_fail (tree_view != NULL, FALSE);
7407 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7408 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
7411 g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
7418 if (x > tree_view->priv->hadjustment->upper)
7424 if (column || cell_x)
7426 GtkTreeViewColumn *tmp_column;
7427 GtkTreeViewColumn *last_column = NULL;
7429 gint remaining_x = x;
7430 gboolean found = FALSE;
7432 for (list = tree_view->priv->columns; list; list = list->next)
7434 tmp_column = list->data;
7436 if (tmp_column->visible == FALSE)
7439 last_column = tmp_column;
7440 if (remaining_x <= tmp_column->width)
7445 *column = tmp_column;
7448 *cell_x = remaining_x;
7452 remaining_x -= tmp_column->width;
7458 *column = last_column;
7461 *cell_x = last_column->width + remaining_x;
7467 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7468 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
7473 if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
7476 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7477 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
7488 *path = _gtk_tree_view_find_path (tree_view, tree, node);
7495 * gtk_tree_view_get_cell_area:
7496 * @tree_view: a #GtkTreeView
7497 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7498 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7499 * @rect: rectangle to fill with cell rect
7501 * Fills the bounding rectangle in tree window coordinates for the cell at the
7502 * row specified by @path and the column specified by @column. If @path is
7503 * %NULL, the y and height fields of the rectangle will be filled with 0. If
7504 * @column is %NULL, the x and width fields will be filled with 0. The sum of
7505 * all cell rects does not cover the entire tree; there are extra pixels in
7506 * between rows, for example. The returned rectangle is equivalent to the
7507 * @cell_area passed to gtk_cell_renderer_render(). This function is only valid
7508 * if #tree_view is realized.
7511 gtk_tree_view_get_cell_area (GtkTreeView *tree_view,
7513 GtkTreeViewColumn *column,
7516 GtkRBTree *tree = NULL;
7517 GtkRBNode *node = NULL;
7518 gint vertical_separator;
7520 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7521 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7522 g_return_if_fail (rect != NULL);
7524 gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
7533 /* Get vertical coords */
7535 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7539 g_warning (G_STRLOC": no row corresponding to path");
7543 /* Remember that the rbtree stores node height including the vertical
7544 * separator, see comment at top of file.
7546 rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
7548 rect->height = CELL_HEIGHT (node, vertical_separator);
7555 gtk_tree_view_get_cell_xrange (tree_view, tree, column, &rect->x, &x2);
7556 rect->width = x2 - rect->x;
7561 * gtk_tree_view_get_background_area:
7562 * @tree_view: a #GtkTreeView
7563 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7564 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7565 * @rect: rectangle to fill with cell background rect
7567 * Fills the bounding rectangle in tree window coordinates for the
7568 * cell at the row specified by @path and the column specified by
7569 * @column. If @path is %NULL, the y and height fields of the
7570 * rectangle will be filled with 0. If @column is %NULL, the x and
7571 * width fields will be filled with 0. The returned rectangle is
7572 * equivalent to the @background_area passed to
7573 * gtk_cell_renderer_render(). These background areas tile to cover
7574 * the entire tree window (except for the area used for header
7575 * buttons). Contrast with the cell_area, returned by
7576 * gtk_tree_view_get_cell_area(), which returns only the cell itself,
7577 * excluding surrounding borders and the tree expander area.
7581 gtk_tree_view_get_background_area (GtkTreeView *tree_view,
7583 GtkTreeViewColumn *column,
7586 GtkRBTree *tree = NULL;
7587 GtkRBNode *node = NULL;
7589 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7590 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7591 g_return_if_fail (rect != NULL);
7600 /* Get vertical coords */
7602 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7606 g_warning (G_STRLOC": no row corresponding to path");
7610 rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
7612 rect->height = BACKGROUND_HEIGHT (node);
7619 gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
7620 rect->width = x2 - rect->x;
7625 * gtk_tree_view_get_visible_rect:
7626 * @tree_view: a #GtkTreeView
7627 * @visible_rect: rectangle to fill
7629 * Fills @visible_rect with the currently-visible region of the
7630 * buffer, in tree coordinates. Convert to widget coordinates with
7631 * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
7632 * 0,0 for row 0 of the tree, and cover the entire scrollable area of
7636 gtk_tree_view_get_visible_rect (GtkTreeView *tree_view,
7637 GdkRectangle *visible_rect)
7641 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7643 widget = GTK_WIDGET (tree_view);
7647 visible_rect->x = tree_view->priv->hadjustment->value;
7648 visible_rect->y = tree_view->priv->vadjustment->value;
7649 visible_rect->width = widget->allocation.width;
7650 visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7655 * gtk_tree_view_widget_to_tree_coords:
7656 * @tree_view: a #GtkTreeView
7657 * @wx: widget X coordinate
7658 * @wy: widget Y coordinate
7659 * @tx: return location for tree X coordinate
7660 * @ty: return location for tree Y coordinate
7662 * Converts widget coordinates to coordinates for the
7663 * tree window (the full scrollable area of the tree).
7667 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
7673 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7677 *tx = wx + tree_view->priv->hadjustment->value;
7682 *ty = wy + tree_view->priv->vadjustment->value;
7687 * gtk_tree_view_tree_to_widget_coords:
7688 * @tree_view: a #GtkTreeView
7689 * @tx: tree X coordinate
7690 * @ty: tree Y coordinate
7691 * @wx: return location for widget X coordinate
7692 * @wy: return location for widget Y coordinate
7694 * Converts tree coordinates (coordinates in full scrollable area of the tree)
7695 * to widget coordinates.
7699 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
7705 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7709 *wx = tx - tree_view->priv->hadjustment->value;
7714 *wy = ty - tree_view->priv->vadjustment->value;
7720 gtk_tree_view_set_rows_drag_source (GtkTreeView *tree_view,
7721 GdkModifierType start_button_mask,
7722 const GtkTargetEntry *targets,
7724 GdkDragAction actions,
7725 GtkTreeViewDraggableFunc row_draggable_func,
7728 TreeViewDragInfo *di;
7730 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7732 di = ensure_info (tree_view);
7733 clear_source_info (di);
7735 di->start_button_mask = start_button_mask;
7736 di->source_target_list = gtk_target_list_new (targets, n_targets);
7737 di->source_actions = actions;
7739 if (row_draggable_func)
7741 di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
7743 g_closure_ref (di->row_draggable_closure);
7744 g_closure_sink (di->row_draggable_closure);
7747 di->source_set = TRUE;
7751 gtk_tree_view_set_rows_drag_dest (GtkTreeView *tree_view,
7752 const GtkTargetEntry *targets,
7754 GdkDragAction actions,
7755 GtkTreeViewDroppableFunc location_droppable_func,
7758 TreeViewDragInfo *di;
7760 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7762 gtk_drag_dest_set (GTK_WIDGET (tree_view),
7768 di = ensure_info (tree_view);
7769 clear_dest_info (di);
7772 di->dest_target_list = gtk_target_list_new (targets, n_targets);
7774 if (location_droppable_func)
7776 di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
7778 g_closure_ref (di->location_droppable_closure);
7779 g_closure_sink (di->location_droppable_closure);
7782 di->dest_set = TRUE;
7786 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
7788 TreeViewDragInfo *di;
7790 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7792 di = get_info (tree_view);
7798 clear_source_info (di);
7799 di->source_set = FALSE;
7802 if (!di->dest_set && !di->source_set)
7803 remove_info (tree_view);
7808 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
7810 TreeViewDragInfo *di;
7812 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7814 di = get_info (tree_view);
7820 gtk_drag_dest_unset (GTK_WIDGET (tree_view));
7821 clear_dest_info (di);
7822 di->dest_set = FALSE;
7825 if (!di->dest_set && !di->source_set)
7826 remove_info (tree_view);
7831 gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
7833 GtkTreeViewDropPosition pos)
7835 GtkTreePath *current_dest;
7836 /* Note; this function is exported to allow a custom DND
7837 * implementation, so it can't touch TreeViewDragInfo
7840 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7842 current_dest = NULL;
7844 if (tree_view->priv->drag_dest_row)
7845 current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7849 gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
7850 gtk_tree_path_free (current_dest);
7853 if (tree_view->priv->drag_dest_row)
7854 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
7856 tree_view->priv->drag_dest_pos = pos;
7860 tree_view->priv->drag_dest_row =
7861 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
7862 gtk_tree_view_queue_draw_path (tree_view, path, NULL);
7865 tree_view->priv->drag_dest_row = NULL;
7869 gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
7871 GtkTreeViewDropPosition *pos)
7873 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7877 if (tree_view->priv->drag_dest_row)
7878 *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7884 *pos = tree_view->priv->drag_dest_pos;
7888 gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
7892 GtkTreeViewDropPosition *pos)
7895 gdouble offset_into_row;
7899 GtkTreeViewColumn *column = NULL;
7900 GtkTreePath *tmp_path = NULL;
7902 /* Note; this function is exported to allow a custom DND
7903 * implementation, so it can't touch TreeViewDragInfo
7906 g_return_val_if_fail (tree_view != NULL, FALSE);
7907 g_return_val_if_fail (drag_x >= 0, FALSE);
7908 g_return_val_if_fail (drag_y >= 0, FALSE);
7909 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
7915 if (tree_view->priv->tree == NULL)
7918 /* remember that drag_x and drag_y are in widget coords, convert to tree window */
7920 gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
7923 /* If in the top quarter of a row, we drop before that row; if
7924 * in the bottom quarter, drop after that row; if in the middle,
7925 * and the row has children, drop into the row.
7928 if (!gtk_tree_view_get_path_at_pos (tree_view,
7929 tree_view->priv->bin_window,
7937 gtk_tree_view_get_background_area (tree_view, tmp_path, column,
7940 offset_into_row = cell_y;
7945 gtk_tree_path_free (tmp_path);
7949 quarter = cell.height / 4.0;
7953 if (offset_into_row < quarter)
7955 *pos = GTK_TREE_VIEW_DROP_BEFORE;
7957 else if (offset_into_row < quarter * 2)
7959 *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
7961 else if (offset_into_row < quarter * 3)
7963 *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
7967 *pos = GTK_TREE_VIEW_DROP_AFTER;
7976 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
7978 * gtk_tree_view_create_row_drag_icon:
7979 * @tree_view: a #GtkTreeView
7980 * @path: a #GtkTreePath in @tree_view
7982 * Creates a GdkPixmap representation of the row at @path. This image is used
7985 * Return value: a newly allocatdd pixmap of the drag icon.
7988 gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
7994 GtkCellRenderer *cell;
7998 GdkRectangle background_area;
8001 /* start drawing inside the black outline */
8003 GdkDrawable *drawable;
8004 gint bin_window_width;
8006 widget = GTK_WIDGET (tree_view);
8008 depth = gtk_tree_path_get_depth (path);
8010 _gtk_tree_view_find_node (tree_view,
8018 if (!gtk_tree_model_get_iter (tree_view->priv->model,
8025 background_area.y = y;
8026 background_area.height = BACKGROUND_HEIGHT (node);
8028 gdk_drawable_get_size (tree_view->priv->bin_window,
8029 &bin_window_width, NULL);
8031 drawable = gdk_pixmap_new (tree_view->priv->bin_window,
8032 bin_window_width + 2,
8033 background_area.height + 2,
8036 gdk_draw_rectangle (drawable,
8037 widget->style->base_gc[GTK_WIDGET_STATE (widget)],
8040 bin_window_width + 2,
8041 background_area.height + 2);
8043 gdk_draw_rectangle (drawable,
8044 widget->style->black_gc,
8047 bin_window_width + 1,
8048 background_area.height + 1);
8050 for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
8052 GtkTreeViewColumn *column = list->data;
8053 GdkRectangle cell_area;
8055 gint vertical_separator;
8057 if (!column->visible)
8060 cell = column->cell;
8061 gtk_tree_view_column_cell_set_cell_data (column,
8062 tree_view->priv->model,
8065 background_area.x = cell_offset;
8066 background_area.width = column->displayed_width;
8068 cell_area = background_area;
8070 gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
8071 cell_area.y += vertical_separator / 2;
8072 cell_area.height -= vertical_separator;
8074 if (i == tree_view->priv->expander_column &&
8075 TREE_VIEW_DRAW_EXPANDERS(tree_view))
8077 cell_area.x += depth * tree_view->priv->tab_offset;
8078 cell_area.width -= depth * tree_view->priv->tab_offset;
8081 g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
8083 gtk_cell_renderer_render (cell,
8091 cell_offset += column->displayed_width;