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"
35 #include <gdk/gdkkeysyms.h>
38 /* The "background" areas of all rows/cells add up to cover the entire tree.
39 * The background includes all inter-row and inter-cell spacing.
40 * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
41 * i.e. just the cells, no spacing.
44 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (_gtk_rbtree_node_find_offset ((tree), (node)) + TREE_VIEW_HEADER_HEIGHT ((tree_view)))
45 #define CELL_FIRST_PIXEL(tree_view,tree,node) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + TREE_VIEW_VERTICAL_SEPARATOR/2)
47 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
48 #define CELL_HEIGHT(node) (BACKGROUND_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPARATOR);
50 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view))
51 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view))
53 typedef struct _GtkTreeViewChild GtkTreeViewChild;
55 struct _GtkTreeViewChild
75 PROP_HEADERS_CLICKABLE,
80 static void gtk_tree_view_init (GtkTreeView *tree_view);
81 static void gtk_tree_view_class_init (GtkTreeViewClass *klass);
82 static void gtk_tree_view_set_property (GObject *object,
86 static void gtk_tree_view_get_property (GObject *object,
91 static void gtk_tree_view_finalize (GObject *object);
94 static void gtk_tree_view_destroy (GtkObject *object);
97 static void gtk_tree_view_setup_model (GtkTreeView *tree_view);
98 static void gtk_tree_view_realize (GtkWidget *widget);
99 static void gtk_tree_view_unrealize (GtkWidget *widget);
100 static void gtk_tree_view_map (GtkWidget *widget);
101 static void gtk_tree_view_size_request (GtkWidget *widget,
102 GtkRequisition *requisition);
103 static void gtk_tree_view_size_allocate (GtkWidget *widget,
104 GtkAllocation *allocation);
105 static gboolean gtk_tree_view_expose (GtkWidget *widget,
106 GdkEventExpose *event);
107 static gboolean gtk_tree_view_motion (GtkWidget *widget,
108 GdkEventMotion *event);
109 static gboolean gtk_tree_view_enter_notify (GtkWidget *widget,
110 GdkEventCrossing *event);
111 static gboolean gtk_tree_view_leave_notify (GtkWidget *widget,
112 GdkEventCrossing *event);
113 static gboolean gtk_tree_view_button_press (GtkWidget *widget,
114 GdkEventButton *event);
115 static gboolean gtk_tree_view_button_release (GtkWidget *widget,
116 GdkEventButton *event);
117 static void gtk_tree_view_set_focus_child (GtkContainer *container,
119 static void gtk_tree_view_draw_focus (GtkWidget *widget);
120 static gint gtk_tree_view_focus_in (GtkWidget *widget,
121 GdkEventFocus *event);
122 static gint gtk_tree_view_focus_out (GtkWidget *widget,
123 GdkEventFocus *event);
124 static gint gtk_tree_view_focus (GtkContainer *container,
125 GtkDirectionType direction);
127 /* container signals */
128 static void gtk_tree_view_remove (GtkContainer *container,
130 static void gtk_tree_view_forall (GtkContainer *container,
131 gboolean include_internals,
132 GtkCallback callback,
133 gpointer callback_data);
135 /* Source side drag signals */
136 static void gtk_tree_view_drag_begin (GtkWidget *widget,
137 GdkDragContext *context);
138 static void gtk_tree_view_drag_end (GtkWidget *widget,
139 GdkDragContext *context);
140 static void gtk_tree_view_drag_data_get (GtkWidget *widget,
141 GdkDragContext *context,
142 GtkSelectionData *selection_data,
145 static void gtk_tree_view_drag_data_delete (GtkWidget *widget,
146 GdkDragContext *context);
148 /* Target side drag signals */
149 static void gtk_tree_view_drag_leave (GtkWidget *widget,
150 GdkDragContext *context,
152 static gboolean gtk_tree_view_drag_motion (GtkWidget *widget,
153 GdkDragContext *context,
157 static gboolean gtk_tree_view_drag_drop (GtkWidget *widget,
158 GdkDragContext *context,
162 static void gtk_tree_view_drag_data_received (GtkWidget *widget,
163 GdkDragContext *context,
166 GtkSelectionData *selection_data,
170 /* tree_model signals */
171 static void gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
173 GtkAdjustment *vadj);
174 static void gtk_tree_view_changed (GtkTreeModel *model,
178 static void gtk_tree_view_inserted (GtkTreeModel *model,
182 static void gtk_tree_view_has_child_toggled (GtkTreeModel *model,
186 static void gtk_tree_view_deleted (GtkTreeModel *model,
190 /* Internal functions */
191 static void gtk_tree_view_unref_tree (GtkTreeView *tree_view,
193 static void gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
196 GdkRectangle *clip_rect);
197 static void gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
199 GdkRectangle *clip_rect);
200 static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
205 static void gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
208 static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view,
211 static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
212 GtkTreeView *tree_view);
213 static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
217 static void gtk_tree_view_build_tree (GtkTreeView *tree_view,
222 gboolean calc_bounds);
223 static void gtk_tree_view_calc_size (GtkTreeView *priv,
227 static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
231 static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
235 static void gtk_tree_view_check_dirty (GtkTreeView *tree_view);
237 static void gtk_tree_view_create_button (GtkTreeView *tree_view,
239 static void gtk_tree_view_create_buttons (GtkTreeView *tree_view);
241 static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
244 static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
245 GdkEventMotion *event);
246 static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view);
247 static void gtk_tree_view_row_activated (GtkTreeView *tree_view,
248 GtkTreeViewColumn *column);
250 static GtkContainerClass *parent_class = NULL;
251 static guint tree_view_signals[LAST_SIGNAL] = { 0 };
253 /* Class Functions */
255 gtk_tree_view_get_type (void)
257 static GtkType tree_view_type = 0;
261 static const GTypeInfo tree_view_info =
263 sizeof (GtkTreeViewClass),
264 NULL, /* base_init */
265 NULL, /* base_finalize */
266 (GClassInitFunc) gtk_tree_view_class_init,
267 NULL, /* class_finalize */
268 NULL, /* class_data */
269 sizeof (GtkTreeView),
271 (GInstanceInitFunc) gtk_tree_view_init
274 tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
277 return tree_view_type;
281 gtk_tree_view_class_init (GtkTreeViewClass *class)
283 GObjectClass *o_class;
284 GtkObjectClass *object_class;
285 GtkWidgetClass *widget_class;
286 GtkContainerClass *container_class;
288 o_class = (GObjectClass *) class;
289 object_class = (GtkObjectClass *) class;
290 widget_class = (GtkWidgetClass *) class;
291 container_class = (GtkContainerClass *) class;
293 parent_class = g_type_class_peek_parent (class);
295 o_class->finalize = gtk_tree_view_finalize;
296 o_class->set_property = gtk_tree_view_set_property;
297 o_class->get_property = gtk_tree_view_get_property;
299 object_class->destroy = gtk_tree_view_destroy;
301 widget_class->realize = gtk_tree_view_realize;
302 widget_class->unrealize = gtk_tree_view_unrealize;
303 widget_class->map = gtk_tree_view_map;
304 widget_class->size_request = gtk_tree_view_size_request;
305 widget_class->size_allocate = gtk_tree_view_size_allocate;
306 widget_class->expose_event = gtk_tree_view_expose;
307 widget_class->motion_notify_event = gtk_tree_view_motion;
308 widget_class->enter_notify_event = gtk_tree_view_enter_notify;
309 widget_class->leave_notify_event = gtk_tree_view_leave_notify;
310 widget_class->button_press_event = gtk_tree_view_button_press;
311 widget_class->button_release_event = gtk_tree_view_button_release;
312 widget_class->focus_in_event = gtk_tree_view_focus_in;
313 widget_class->focus_out_event = gtk_tree_view_focus_out;
315 widget_class->drag_begin = gtk_tree_view_drag_begin;
316 widget_class->drag_end = gtk_tree_view_drag_end;
317 widget_class->drag_data_get = gtk_tree_view_drag_data_get;
318 widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
320 widget_class->drag_leave = gtk_tree_view_drag_leave;
321 widget_class->drag_motion = gtk_tree_view_drag_motion;
322 widget_class->drag_drop = gtk_tree_view_drag_drop;
323 widget_class->drag_data_received = gtk_tree_view_drag_data_received;
325 container_class->forall = gtk_tree_view_forall;
326 container_class->remove = gtk_tree_view_remove;
327 container_class->focus = gtk_tree_view_focus;
329 class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
331 g_object_class_install_property (o_class,
333 g_param_spec_object ("model",
335 _("The model for the tree view"),
339 g_object_class_install_property (o_class,
341 g_param_spec_object ("hadjustment",
342 _("Horizontal Adjustment"),
343 _("Horizontal Adjustment for the widget"),
347 g_object_class_install_property (o_class,
349 g_param_spec_object ("vadjustment",
350 _("Vertical Adjustment"),
351 _("Vertical Adjustment for the widget"),
355 g_object_class_install_property (o_class,
356 PROP_HEADERS_VISIBLE,
357 g_param_spec_boolean ("headers_visible",
359 _("Show the column header buttons"),
363 g_object_class_install_property (o_class,
364 PROP_HEADERS_CLICKABLE,
365 g_param_spec_boolean ("headers_clickable",
366 _("Headers Clickable"),
367 _("Column headers respond to click events"),
371 g_object_class_install_property (o_class,
372 PROP_EXPANDER_COLUMN,
373 g_param_spec_uint ("expander_column",
375 _("Set the column number for the expander column"),
381 g_object_class_install_property (o_class,
383 g_param_spec_boolean ("rules_hint",
385 _("Set a hint to the theme engine to draw rows in alternating colors"),
389 widget_class->set_scroll_adjustments_signal =
390 gtk_signal_new ("set_scroll_adjustments",
392 GTK_CLASS_TYPE (object_class),
393 GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
394 gtk_marshal_VOID__OBJECT_OBJECT,
396 GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
398 tree_view_signals[ROW_ACTIVATED] = gtk_signal_new ("row_activated",
399 GTK_RUN_LAST | GTK_RUN_ACTION,
400 GTK_CLASS_TYPE (object_class),
401 GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
402 gtk_marshal_VOID__OBJECT,
404 GTK_TYPE_TREE_VIEW_COLUMN);
409 gtk_tree_view_init (GtkTreeView *tree_view)
411 tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
413 GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
415 tree_view->priv->model = NULL;
416 tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
417 tree_view->priv->tab_offset = TREE_VIEW_EXPANDER_WIDTH;
418 tree_view->priv->n_columns = 0;
419 tree_view->priv->columns = NULL;
420 tree_view->priv->button_pressed_node = NULL;
421 tree_view->priv->button_pressed_tree = NULL;
422 tree_view->priv->prelight_node = NULL;
423 tree_view->priv->header_height = 1;
424 tree_view->priv->x_drag = 0;
425 tree_view->priv->drag_pos = -1;
426 tree_view->priv->selection = NULL;
427 tree_view->priv->anchor = NULL;
428 tree_view->priv->cursor = NULL;
429 tree_view->priv->header_has_focus = FALSE;
430 tree_view->priv->pressed_button = -1;
431 tree_view->priv->press_start_x = -1;
432 tree_view->priv->press_start_y = -1;
434 gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
435 _gtk_tree_view_update_size (tree_view);
443 gtk_tree_view_finalize (GObject *object)
445 GtkTreeView *tree_view = (GtkTreeView *) object;
447 g_free (tree_view->priv);
449 if (G_OBJECT_CLASS (parent_class)->finalize)
450 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
454 gtk_tree_view_destroy (GtkObject *object)
456 GtkTreeView *tree_view = (GtkTreeView *) object;
460 if (tree_view->priv->tree != NULL)
462 gtk_tree_view_unref_tree (tree_view, tree_view->priv->tree);
463 _gtk_rbtree_free (tree_view->priv->tree);
464 tree_view->priv->tree = NULL;
467 if (tree_view->priv->model != NULL)
469 g_object_unref (G_OBJECT (tree_view->priv->model));
470 tree_view->priv->model = NULL;
473 if (tree_view->priv->columns != NULL)
475 for (list = tree_view->priv->columns; list; list = list->next)
476 g_object_unref (G_OBJECT (list->data));
477 g_list_free (tree_view->priv->columns);
478 tree_view->priv->columns = NULL;
481 if (tree_view->priv->selection != NULL)
483 _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
484 g_object_unref (tree_view->priv->selection);
485 tree_view->priv->selection = NULL;
488 if (tree_view->priv->anchor != NULL)
490 gtk_tree_row_reference_free (tree_view->priv->anchor);
491 tree_view->priv->anchor = NULL;
494 if (tree_view->priv->scroll_to_path != NULL)
496 gtk_tree_path_free (tree_view->priv->scroll_to_path);
497 tree_view->priv->scroll_to_path = NULL;
500 if (tree_view->priv->drag_dest_row != NULL)
502 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
503 tree_view->priv->drag_dest_row = NULL;
506 if (tree_view->priv->cursor)
508 gtk_tree_row_reference_free (tree_view->priv->cursor);
509 tree_view->priv->cursor = NULL;
512 if (GTK_OBJECT_CLASS (parent_class)->destroy)
513 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
520 gtk_tree_view_set_property (GObject *object,
525 GtkTreeView *tree_view;
527 tree_view = GTK_TREE_VIEW (object);
532 gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (g_value_get_object (value)));
534 case PROP_HADJUSTMENT:
535 gtk_tree_view_set_hadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
537 case PROP_VADJUSTMENT:
538 gtk_tree_view_set_vadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
540 case PROP_HEADERS_VISIBLE:
541 gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
543 case PROP_HEADERS_CLICKABLE:
544 gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
546 case PROP_EXPANDER_COLUMN:
547 gtk_tree_view_set_expander_column (tree_view, g_value_get_uint (value));
549 case PROP_RULES_HINT:
550 gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
558 gtk_tree_view_get_property (GObject *object,
563 GtkTreeView *tree_view;
565 tree_view = GTK_TREE_VIEW (object);
570 g_value_set_object (value, G_OBJECT (tree_view->priv->model));
572 case PROP_HADJUSTMENT:
573 g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
575 case PROP_VADJUSTMENT:
576 g_value_set_object (value, G_OBJECT (tree_view->priv->vadjustment));
578 case PROP_HEADERS_VISIBLE:
579 g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
581 case PROP_HEADERS_CLICKABLE:
582 /* g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view)); */
584 case PROP_EXPANDER_COLUMN:
585 g_value_set_uint (value, tree_view->priv->expander_column);
587 case PROP_RULES_HINT:
588 g_value_set_boolean (value, tree_view->priv->has_rules);
591 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
600 gtk_tree_view_realize (GtkWidget *widget)
603 GtkTreeView *tree_view;
605 GdkWindowAttr attributes;
606 gint attributes_mask;
608 g_return_if_fail (widget != NULL);
609 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
611 tree_view = GTK_TREE_VIEW (widget);
613 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
614 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
616 /* Make the main, clipping window */
617 attributes.window_type = GDK_WINDOW_CHILD;
618 attributes.x = widget->allocation.x;
619 attributes.y = widget->allocation.y;
620 attributes.width = widget->allocation.width;
621 attributes.height = widget->allocation.height;
622 attributes.wclass = GDK_INPUT_OUTPUT;
623 attributes.visual = gtk_widget_get_visual (widget);
624 attributes.colormap = gtk_widget_get_colormap (widget);
625 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
627 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
629 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
630 &attributes, attributes_mask);
631 gdk_window_set_user_data (widget->window, widget);
633 /* Make the window for the tree */
636 attributes.width = tree_view->priv->width;
637 attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
638 attributes.event_mask = GDK_EXPOSURE_MASK |
640 GDK_POINTER_MOTION_MASK |
641 GDK_ENTER_NOTIFY_MASK |
642 GDK_LEAVE_NOTIFY_MASK |
643 GDK_BUTTON_PRESS_MASK |
644 GDK_BUTTON_RELEASE_MASK |
645 gtk_widget_get_events (widget);
647 tree_view->priv->bin_window = gdk_window_new (widget->window,
648 &attributes, attributes_mask);
649 gdk_window_set_user_data (tree_view->priv->bin_window, widget);
651 /* Make the column header window */
654 attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
655 attributes.height = tree_view->priv->header_height;
656 attributes.event_mask = (GDK_EXPOSURE_MASK |
658 GDK_BUTTON_PRESS_MASK |
659 GDK_BUTTON_RELEASE_MASK |
661 GDK_KEY_RELEASE_MASK) |
662 gtk_widget_get_events (widget);
664 tree_view->priv->header_window = gdk_window_new (widget->window,
665 &attributes, attributes_mask);
666 gdk_window_set_user_data (tree_view->priv->header_window, widget);
669 values.foreground = (widget->style->white.pixel==0 ?
670 widget->style->black:widget->style->white);
671 values.function = GDK_XOR;
672 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
673 tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
678 /* Add them all up. */
679 widget->style = gtk_style_attach (widget->style, widget->window);
680 gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
681 gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
682 gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
684 tmp_list = tree_view->priv->children;
687 GtkTreeViewChild *child = tmp_list->data;
688 tmp_list = tmp_list->next;
690 gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
693 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
694 _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
696 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
698 if (tree_view->priv->scroll_to_path != NULL ||
699 tree_view->priv->scroll_to_column != NULL)
701 gtk_tree_view_scroll_to_cell (tree_view,
702 tree_view->priv->scroll_to_path,
703 tree_view->priv->scroll_to_column,
704 tree_view->priv->scroll_to_row_align,
705 tree_view->priv->scroll_to_col_align);
706 if (tree_view->priv->scroll_to_path)
708 gtk_tree_path_free (tree_view->priv->scroll_to_path);
709 tree_view->priv->scroll_to_path = NULL;
711 tree_view->priv->scroll_to_column = NULL;
716 gtk_tree_view_unrealize (GtkWidget *widget)
718 GtkTreeView *tree_view;
721 g_return_if_fail (widget != NULL);
722 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
724 tree_view = GTK_TREE_VIEW (widget);
726 if (tree_view->priv->scroll_timeout != 0)
728 gtk_timeout_remove (tree_view->priv->scroll_timeout);
729 tree_view->priv->scroll_timeout = 0;
732 if (tree_view->priv->open_dest_timeout != 0)
734 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
735 tree_view->priv->open_dest_timeout = 0;
738 for (list = tree_view->priv->columns; list; list = list->next)
739 _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
741 gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
742 gdk_window_destroy (tree_view->priv->bin_window);
743 tree_view->priv->bin_window = NULL;
745 gdk_window_set_user_data (tree_view->priv->header_window, NULL);
746 gdk_window_destroy (tree_view->priv->header_window);
747 tree_view->priv->header_window = NULL;
749 gdk_cursor_destroy (tree_view->priv->cursor_drag);
750 gdk_gc_destroy (tree_view->priv->xor_gc);
752 /* GtkWidget::unrealize destroys children and widget->window */
754 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
755 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
759 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
763 g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
765 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
767 GtkTreeViewColumn *column;
769 for (list = tree_view->priv->columns; list; list = list->next)
772 if (GTK_WIDGET_VISIBLE (column->button) &&
773 !GTK_WIDGET_MAPPED (column->button))
774 gtk_widget_map (column->button);
776 for (list = tree_view->priv->columns; list; list = list->next)
779 if (column->visible == FALSE)
781 if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
783 gdk_window_raise (column->window);
784 gdk_window_show (column->window);
787 gdk_window_hide (column->window);
789 gdk_window_show (tree_view->priv->header_window);
794 gtk_tree_view_map (GtkWidget *widget)
797 GtkTreeView *tree_view;
799 g_return_if_fail (widget != NULL);
800 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
802 tree_view = GTK_TREE_VIEW (widget);
804 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
806 tmp_list = tree_view->priv->children;
809 GtkTreeViewChild *child = tmp_list->data;
810 tmp_list = tmp_list->next;
812 if (GTK_WIDGET_VISIBLE (child->widget))
814 if (!GTK_WIDGET_MAPPED (child->widget))
815 gtk_widget_map (child->widget);
818 gdk_window_show (tree_view->priv->bin_window);
820 gtk_tree_view_map_buttons (tree_view);
822 gdk_window_show (widget->window);
826 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
830 tree_view->priv->header_height = 1;
832 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
834 for (list = tree_view->priv->columns; list; list = list->next)
836 GtkRequisition requisition;
837 GtkTreeViewColumn *column;
841 gtk_widget_size_request (column->button, &requisition);
843 gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
844 tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
850 gtk_tree_view_size_request (GtkWidget *widget,
851 GtkRequisition *requisition)
853 GtkTreeView *tree_view;
856 g_return_if_fail (widget != NULL);
857 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
859 tree_view = GTK_TREE_VIEW (widget);
861 requisition->width = 200;
862 requisition->height = 200;
864 tmp_list = tree_view->priv->children;
868 GtkTreeViewChild *child = tmp_list->data;
869 GtkRequisition child_requisition;
871 tmp_list = tmp_list->next;
873 if (GTK_WIDGET_VISIBLE (child->widget))
874 gtk_widget_size_request (child->widget, &child_requisition);
877 gtk_tree_view_size_request_buttons (tree_view);
881 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
883 GtkTreeView *tree_view;
885 GtkTreeViewColumn *column;
886 GtkAllocation allocation;
889 tree_view = GTK_TREE_VIEW (widget);
892 allocation.height = tree_view->priv->header_height;
894 for (list = tree_view->priv->columns; list != NULL; list = list->next)
898 if (!column->visible)
901 allocation.x = width;
902 allocation.width = column->displayed_width;
903 width += column->width;
904 gtk_widget_size_allocate (column->button, &allocation);
907 gdk_window_move_resize (column->window,
908 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
910 TREE_VIEW_DRAG_WIDTH, allocation.height);
915 gtk_tree_view_size_allocate (GtkWidget *widget,
916 GtkAllocation *allocation)
919 GtkTreeView *tree_view;
921 g_return_if_fail (widget != NULL);
922 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
924 widget->allocation = *allocation;
926 tree_view = GTK_TREE_VIEW (widget);
928 gtk_tree_view_check_dirty (tree_view);
930 tmp_list = tree_view->priv->children;
934 GtkAllocation allocation;
935 GtkRequisition requisition;
937 GtkTreeViewChild *child = tmp_list->data;
938 tmp_list = tmp_list->next;
940 allocation.x = child->x;
941 allocation.y = child->y;
942 gtk_widget_get_child_requisition (child->widget, &requisition);
943 allocation.width = requisition.width;
944 allocation.height = requisition.height;
946 gtk_widget_size_allocate (child->widget, &allocation);
949 if (GTK_WIDGET_REALIZED (widget))
951 gdk_window_move_resize (widget->window,
952 allocation->x, allocation->y,
953 allocation->width, allocation->height);
955 gdk_window_move_resize (tree_view->priv->header_window,
957 MAX (tree_view->priv->width, allocation->width),
958 tree_view->priv->header_height);
960 if (tree_view->priv->width < allocation->width)
961 gdk_window_resize (tree_view->priv->bin_window,
963 tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
965 _gtk_tree_view_update_col_width (tree_view);
968 gtk_tree_view_size_allocate_buttons (widget);
970 tree_view->priv->hadjustment->page_size = allocation->width;
971 tree_view->priv->hadjustment->page_increment = allocation->width / 2;
972 tree_view->priv->hadjustment->lower = 0;
973 tree_view->priv->hadjustment->upper = tree_view->priv->width;
975 if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
976 tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
977 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
979 tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
980 tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
981 tree_view->priv->vadjustment->lower = 0;
982 tree_view->priv->vadjustment->upper = tree_view->priv->height;
984 if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
985 gtk_adjustment_set_value (tree_view->priv->vadjustment,
986 (gfloat) MAX (tree_view->priv->height - allocation->height, 0));
988 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
993 gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
999 GtkCellRenderer *cell;
1003 GdkRectangle background_area;
1006 /* start drawing inside the black outline */
1008 GdkDrawable *drawable;
1009 gint bin_window_width;
1011 widget = GTK_WIDGET (tree_view);
1013 depth = gtk_tree_path_get_depth (path);
1015 _gtk_tree_view_find_node (tree_view,
1023 if (!gtk_tree_model_get_iter (tree_view->priv->model,
1030 background_area.y = y;
1031 background_area.height = BACKGROUND_HEIGHT (node);
1033 gdk_drawable_get_size (tree_view->priv->bin_window,
1034 &bin_window_width, NULL);
1036 drawable = gdk_pixmap_new (tree_view->priv->bin_window,
1037 bin_window_width + 2,
1038 background_area.height + 2,
1041 gdk_draw_rectangle (drawable,
1042 widget->style->base_gc[GTK_WIDGET_STATE (widget)],
1045 bin_window_width + 2,
1046 background_area.height + 2);
1048 gdk_draw_rectangle (drawable,
1049 widget->style->black_gc,
1052 bin_window_width + 1,
1053 background_area.height + 1);
1055 for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1057 GtkTreeViewColumn *column = list->data;
1058 GdkRectangle cell_area;
1061 if (!column->visible)
1064 cell = column->cell;
1065 gtk_tree_view_column_set_cell_data (column,
1066 tree_view->priv->model,
1069 background_area.x = cell_offset;
1070 background_area.width = column->displayed_width;
1072 cell_area = background_area;
1074 cell_area.y += TREE_VIEW_VERTICAL_SEPARATOR / 2;
1075 cell_area.height -= TREE_VIEW_VERTICAL_SEPARATOR;
1077 if (i == tree_view->priv->expander_column &&
1078 TREE_VIEW_DRAW_EXPANDERS(tree_view))
1080 cell_area.x += depth * tree_view->priv->tab_offset;
1081 cell_area.width -= depth * tree_view->priv->tab_offset;
1084 g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
1086 gtk_cell_renderer_render (cell,
1094 cell_offset += column->displayed_width;
1100 /* Warning: Very scary function.
1101 * Modify at your own risk
1104 gtk_tree_view_bin_expose (GtkWidget *widget,
1105 GdkEventExpose *event)
1107 GtkTreeView *tree_view;
1112 GtkRBNode *cursor = NULL;
1113 GtkRBTree *cursor_tree = NULL;
1114 GtkRBNode *drag_highlight = NULL;
1115 GtkRBTree *drag_highlight_tree = NULL;
1117 GtkCellRenderer *cell;
1119 gint y_offset, x_offset, cell_offset;
1122 GdkRectangle background_area;
1123 GdkRectangle cell_area;
1126 gint bin_window_width;
1127 GtkTreePath *cursor_path;
1128 GtkTreePath *drag_dest_path;
1131 g_return_val_if_fail (widget != NULL, FALSE);
1132 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1134 tree_view = GTK_TREE_VIEW (widget);
1136 if (tree_view->priv->tree == NULL)
1139 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
1140 /* we want to account for a potential HEADER offset.
1141 * That is, if the header exists, we want to offset our event by its
1142 * height to find the right node.
1144 new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
1146 /* y_offset is the */
1148 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1149 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1151 &node) + new_y - event->area.y;
1155 /* find the path for the node */
1156 path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
1159 gtk_tree_model_get_iter (tree_view->priv->model,
1162 depth = gtk_tree_path_get_depth (path);
1163 gtk_tree_path_free (path);
1166 drag_dest_path = NULL;
1168 if (tree_view->priv->cursor)
1169 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
1172 _gtk_tree_view_find_node (tree_view, cursor_path,
1173 &cursor_tree, &cursor);
1175 if (tree_view->priv->drag_dest_row)
1176 drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
1179 _gtk_tree_view_find_node (tree_view, drag_dest_path,
1180 &drag_highlight_tree, &drag_highlight);
1182 gdk_drawable_get_size (tree_view->priv->bin_window,
1183 &bin_window_width, NULL);
1185 for (last_column = g_list_last (tree_view->priv->columns);
1187 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
1188 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
1189 last_column = last_column->prev)
1192 /* Actually process the expose event. To do this, we want to
1193 * start at the first node of the event, and walk the tree in
1194 * order, drawing each successive node.
1199 /* Need to think about this more.
1200 if (tree_view->priv->show_expanders)
1201 max_height = MAX (TREE_VIEW_EXPANDER_MIN_HEIGHT, GTK_RBNODE_GET_HEIGHT (node));
1206 max_height = BACKGROUND_HEIGHT (node);
1208 x_offset = -event->area.x;
1210 highlight_x = 0; /* should match x coord of first cell */
1212 background_area.y = y_offset + event->area.y;
1213 background_area.height = max_height;
1216 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
1217 flags |= GTK_CELL_RENDERER_PRELIT;
1219 parity = _gtk_rbtree_node_find_parity (tree, node);
1221 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1222 flags |= GTK_CELL_RENDERER_SELECTED;
1224 for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1226 GtkTreeViewColumn *column = list->data;
1227 const gchar *detail = NULL;
1229 if (!column->visible)
1232 if (cell_offset > event->area.x + event->area.width ||
1233 cell_offset + column->displayed_width < event->area.x)
1235 cell_offset += column->displayed_width;
1239 if (column->show_sort_indicator)
1240 flags |= GTK_CELL_RENDERER_SORTED;
1242 flags &= ~GTK_CELL_RENDERER_SORTED;
1244 cell = column->cell;
1245 gtk_tree_view_column_set_cell_data (column,
1246 tree_view->priv->model,
1249 background_area.x = cell_offset;
1250 background_area.width = column->displayed_width;
1252 cell_area = background_area;
1253 cell_area.y += TREE_VIEW_VERTICAL_SEPARATOR / 2;
1254 cell_area.height -= TREE_VIEW_VERTICAL_SEPARATOR;
1256 /* Select the detail for drawing the cell. relevant
1257 * factors are parity, sortedness, and whether to
1261 /* FIXME when we have style properties, clean this up.
1264 if (tree_view->priv->has_rules)
1266 if (flags & GTK_CELL_RENDERER_SORTED)
1269 detail = "cell_odd_ruled_sorted";
1271 detail = "cell_even_ruled_sorted";
1276 detail = "cell_odd_ruled";
1278 detail = "cell_even_ruled";
1283 if (flags & GTK_CELL_RENDERER_SORTED)
1286 detail = "cell_odd_sorted";
1288 detail = "cell_even_sorted";
1293 detail = "cell_odd";
1295 detail = "cell_even";
1301 /* Draw background */
1302 gtk_paint_flat_box (widget->style,
1304 (flags & GTK_CELL_RENDERER_SELECTED) ?
1305 GTK_STATE_SELECTED : GTK_STATE_NORMAL,
1312 background_area.width,
1313 background_area.height);
1315 if (i == tree_view->priv->expander_column &&
1316 TREE_VIEW_DRAW_EXPANDERS(tree_view))
1320 cell_area.x += depth*tree_view->priv->tab_offset;
1321 cell_area.width -= depth*tree_view->priv->tab_offset;
1323 /* If we have an expander column, the highlight underline
1324 * starts with that column, so that it indicates which
1325 * level of the tree we're dropping at.
1327 highlight_x = cell_area.x;
1329 g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
1331 gtk_cell_renderer_render (cell,
1339 if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
1342 gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
1343 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1352 g_object_get (G_OBJECT (cell), "visible", &visible, NULL);
1355 gtk_cell_renderer_render (cell,
1363 cell_offset += column->displayed_width;
1366 if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
1367 gtk_tree_view_draw_focus (widget);
1369 if (node == drag_highlight)
1371 /* Draw indicator for the drop
1373 gint highlight_y = -1;
1374 GtkRBTree *tree = NULL;
1375 GtkRBNode *node = NULL;
1378 switch (tree_view->priv->drag_dest_pos)
1380 case GTK_TREE_VIEW_DROP_BEFORE:
1381 highlight_y = background_area.y - TREE_VIEW_VERTICAL_SEPARATOR/2;
1384 case GTK_TREE_VIEW_DROP_AFTER:
1385 highlight_y = background_area.y + background_area.height + TREE_VIEW_VERTICAL_SEPARATOR/2;
1388 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1389 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1390 _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
1394 gdk_drawable_get_size (tree_view->priv->bin_window,
1396 gtk_paint_focus (widget->style,
1397 tree_view->priv->bin_window,
1401 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
1402 width - 1, BACKGROUND_HEIGHT (node) - 1);
1407 if (highlight_y >= 0)
1409 gdk_draw_line (event->window,
1410 widget->style->black_gc,
1413 bin_window_width - highlight_x,
1418 y_offset += max_height;
1421 GtkTreeIter parent = iter;
1424 tree = node->children;
1427 g_assert (node != tree->nil);
1429 while (node->left != tree->nil)
1431 has_child = gtk_tree_model_iter_children (tree_view->priv->model,
1434 cell = gtk_tree_view_get_column (tree_view, 0)->cell;
1438 TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
1442 gboolean done = FALSE;
1445 node = _gtk_rbtree_next (tree, node);
1448 gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
1449 cell = gtk_tree_view_get_column (tree_view, 0)->cell;
1453 TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
1457 GtkTreeIter parent_iter = iter;
1458 gboolean has_parent;
1460 node = tree->parent_node;
1461 tree = tree->parent_tree;
1463 /* we've run out of tree. It's okay to return though, as
1464 * we'd only break out of the while loop below. */
1466 has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
1472 TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
1478 while (y_offset < event->area.height);
1481 gtk_tree_path_free (cursor_path);
1484 gtk_tree_path_free (drag_dest_path);
1490 gtk_tree_view_expose (GtkWidget *widget,
1491 GdkEventExpose *event)
1493 GtkTreeView *tree_view;
1495 g_return_val_if_fail (widget != NULL, FALSE);
1496 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1498 tree_view = GTK_TREE_VIEW (widget);
1500 if (event->window == tree_view->priv->bin_window)
1501 return gtk_tree_view_bin_expose (widget, event);
1507 coords_are_over_arrow (GtkTreeView *tree_view,
1510 /* these are in tree window coords */
1517 if (!GTK_WIDGET_REALIZED (tree_view))
1520 if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1523 arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
1525 arrow.height = BACKGROUND_HEIGHT (node);
1527 gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
1529 arrow.width = x2 - arrow.x;
1531 return (x >= arrow.x &&
1532 x < (arrow.x + arrow.height) &&
1534 y < (arrow.y + arrow.height));
1538 do_unprelight (GtkTreeView *tree_view,
1539 /* these are in tree window coords */
1543 if (tree_view->priv->prelight_node == NULL)
1546 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1548 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1549 !coords_are_over_arrow (tree_view,
1550 tree_view->priv->prelight_tree,
1551 tree_view->priv->prelight_node,
1554 /* We need to unprelight the old arrow. */
1556 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1558 gtk_tree_view_draw_arrow (tree_view,
1559 tree_view->priv->prelight_tree,
1560 tree_view->priv->prelight_node,
1566 tree_view->priv->prelight_node = NULL;
1567 tree_view->priv->prelight_tree = NULL;
1571 do_prelight (GtkTreeView *tree_view,
1574 /* these are in tree window coords */
1578 if (coords_are_over_arrow (tree_view, tree, node, x, y))
1579 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1581 tree_view->priv->prelight_node = node;
1582 tree_view->priv->prelight_tree = tree;
1584 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1588 ensure_unprelighted (GtkTreeView *tree_view)
1590 do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
1594 gtk_tree_view_motion (GtkWidget *widget,
1595 GdkEventMotion *event)
1597 GtkTreeView *tree_view;
1601 GtkRBTree *old_prelight_tree;
1602 GtkRBNode *old_prelight_node;
1604 tree_view = (GtkTreeView *) widget;
1606 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1611 if (event->is_hint || event->window != widget->window)
1612 gtk_widget_get_pointer (widget, &x, NULL);
1616 new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos, &x);
1617 if (x != tree_view->priv->x_drag)
1619 gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos), new_width);
1622 /* FIXME: Do we need to scroll */
1623 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1627 /* Sanity check it */
1628 if (event->window != tree_view->priv->bin_window)
1631 if (tree_view->priv->tree == NULL)
1634 gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
1636 old_prelight_tree = tree_view->priv->prelight_tree;
1637 old_prelight_node = tree_view->priv->prelight_node;
1639 do_unprelight (tree_view, event->x, event->y);
1641 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1643 _gtk_rbtree_find_offset (tree_view->priv->tree,
1644 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1651 /* If we are currently pressing down a button, we don't want to prelight anything else. */
1652 if ((tree_view->priv->button_pressed_node != NULL) &&
1653 (tree_view->priv->button_pressed_node != node))
1657 do_prelight (tree_view, tree, node, event->x, new_y);
1659 if (old_prelight_node != tree_view->priv->prelight_node)
1661 if (old_prelight_node)
1662 gtk_tree_view_queue_draw_node (tree_view,
1667 if (tree_view->priv->prelight_node)
1668 gtk_tree_view_queue_draw_node (tree_view,
1669 tree_view->priv->prelight_tree,
1670 tree_view->priv->prelight_node,
1677 /* FIXME Is this function necessary? Can I get an enter_notify event
1678 * w/o either an expose event or a mouse motion event?
1681 gtk_tree_view_enter_notify (GtkWidget *widget,
1682 GdkEventCrossing *event)
1684 GtkTreeView *tree_view;
1689 g_return_val_if_fail (widget != NULL, FALSE);
1690 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1692 tree_view = GTK_TREE_VIEW (widget);
1694 /* Sanity check it */
1695 if (event->window != tree_view->priv->bin_window)
1698 if (tree_view->priv->tree == NULL)
1701 if ((tree_view->priv->button_pressed_node != NULL) &&
1702 (tree_view->priv->button_pressed_node != node))
1705 /* find the node internally */
1706 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1708 _gtk_rbtree_find_offset (tree_view->priv->tree,
1709 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1716 do_prelight (tree_view, tree, node, event->x, new_y);
1718 if (tree_view->priv->prelight_node)
1719 gtk_tree_view_queue_draw_node (tree_view,
1720 tree_view->priv->prelight_tree,
1721 tree_view->priv->prelight_node,
1728 gtk_tree_view_leave_notify (GtkWidget *widget,
1729 GdkEventCrossing *event)
1731 GtkTreeView *tree_view;
1733 g_return_val_if_fail (widget != NULL, FALSE);
1734 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1736 tree_view = GTK_TREE_VIEW (widget);
1738 if (tree_view->priv->prelight_node)
1739 gtk_tree_view_queue_draw_node (tree_view,
1740 tree_view->priv->prelight_tree,
1741 tree_view->priv->prelight_node,
1744 ensure_unprelighted (tree_view);
1750 gtk_tree_view_button_press (GtkWidget *widget,
1751 GdkEventButton *event)
1753 GtkTreeView *tree_view;
1755 GtkTreeViewColumn *column = NULL;
1757 GdkRectangle background_area;
1758 GdkRectangle cell_area;
1760 g_return_val_if_fail (widget != NULL, FALSE);
1761 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1762 g_return_val_if_fail (event != NULL, FALSE);
1764 tree_view = GTK_TREE_VIEW (widget);
1766 if (event->window == tree_view->priv->bin_window)
1775 GtkTreeViewColumn *column = NULL;
1777 if (!GTK_WIDGET_HAS_FOCUS (widget))
1778 gtk_widget_grab_focus (widget);
1779 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1781 /* are we in an arrow? */
1782 if (tree_view->priv->prelight_node &&
1783 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1785 if (event->button == 1)
1787 gtk_grab_add (widget);
1788 tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1789 tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1790 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1791 tree_view->priv->prelight_tree,
1792 tree_view->priv->prelight_node,
1799 /* find the node that was clicked */
1800 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1801 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1802 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1804 &node) + new_y - (gint)event->y;
1807 /* We clicked in dead space */
1810 /* Get the path and the node */
1811 path = _gtk_tree_view_find_path (tree_view, tree, node);
1812 depth = gtk_tree_path_get_depth (path);
1813 background_area.y = y_offset + event->y + TREE_VIEW_VERTICAL_SEPARATOR;
1814 background_area.height = GTK_RBNODE_GET_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPARATOR;
1815 background_area.x = 0;
1816 /* Let the cell have a chance at selecting it. */
1818 for (i = 0, list = tree_view->priv->columns; i < tree_view->priv->n_columns; i++, list = list->next)
1820 GtkCellRenderer *cell;
1823 gboolean can_activate;
1825 column = list->data;
1827 if (!column->visible)
1830 background_area.width = column->displayed_width;
1831 if (i == tree_view->priv->expander_column &&
1832 TREE_VIEW_DRAW_EXPANDERS(tree_view))
1834 cell_area = background_area;
1835 cell_area.x += depth*tree_view->priv->tab_offset;
1836 cell_area.width -= depth*tree_view->priv->tab_offset;
1840 cell_area = background_area;
1843 cell = column->cell;
1845 if ((background_area.x > (gint) event->x) ||
1846 (background_area.y > (gint) event->y) ||
1847 (background_area.x + background_area.width <= (gint) event->x) ||
1848 (background_area.y + background_area.height <= (gint) event->y))
1850 background_area.x += background_area.width;
1854 gtk_tree_model_get_iter (tree_view->priv->model,
1857 gtk_tree_view_column_set_cell_data (column,
1858 tree_view->priv->model,
1861 path_string = gtk_tree_path_to_string (path);
1863 g_object_get (G_OBJECT (cell),
1864 "visible", &visible,
1865 "can_activate", &can_activate,
1869 gtk_cell_renderer_event (cell, (GdkEvent *)event,
1870 widget, path_string,
1874 g_free (path_string);
1875 gtk_tree_path_free (path);
1880 g_free (path_string);
1888 /* Save press to possibly begin a drag
1890 if (tree_view->priv->pressed_button < 0)
1892 tree_view->priv->pressed_button = event->button;
1893 tree_view->priv->press_start_x = event->x;
1894 tree_view->priv->press_start_y = event->y;
1897 /* Handle the selection */
1898 if (tree_view->priv->selection == NULL)
1899 tree_view->priv->selection =
1900 _gtk_tree_selection_new_with_tree_view (tree_view);
1902 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
1907 gtk_tree_path_free (path);
1909 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1911 gtk_tree_view_row_activated (tree_view, column );
1916 for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1918 column = list->data;
1919 if (event->window == column->window &&
1920 column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE &&
1925 if (gdk_pointer_grab (column->window, FALSE,
1926 GDK_POINTER_MOTION_HINT_MASK |
1927 GDK_BUTTON1_MOTION_MASK |
1928 GDK_BUTTON_RELEASE_MASK,
1929 NULL, NULL, event->time))
1932 gtk_grab_add (widget);
1933 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1935 /* block attached dnd signal handler */
1936 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1938 gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1940 if (!GTK_WIDGET_HAS_FOCUS (widget))
1941 gtk_widget_grab_focus (widget);
1943 tree_view->priv->drag_pos = i;
1944 tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1951 gtk_tree_view_button_release (GtkWidget *widget,
1952 GdkEventButton *event)
1954 GtkTreeView *tree_view;
1956 g_return_val_if_fail (widget != NULL, FALSE);
1957 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1958 g_return_val_if_fail (event != NULL, FALSE);
1960 tree_view = GTK_TREE_VIEW (widget);
1962 if (tree_view->priv->pressed_button == event->button)
1963 tree_view->priv->pressed_button = -1;
1965 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1972 i = tree_view->priv->drag_pos;
1973 tree_view->priv->drag_pos = -1;
1975 /* unblock attached dnd signal handler */
1976 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1978 gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1980 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1981 gtk_widget_get_pointer (widget, &x, NULL);
1982 gtk_grab_remove (widget);
1983 gdk_pointer_ungrab (event->time);
1985 width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1986 gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1990 if (tree_view->priv->button_pressed_node == NULL)
1993 if (event->button == 1)
1995 gtk_grab_remove (widget);
1996 if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1997 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2002 /* Actually activate the node */
2003 if (tree_view->priv->button_pressed_node->children == NULL)
2006 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
2007 tree_view->priv->button_pressed_tree,
2008 tree_view->priv->button_pressed_node);
2009 tree_view->priv->button_pressed_node->children = _gtk_rbtree_new ();
2010 tree_view->priv->button_pressed_node->children->parent_tree = tree_view->priv->button_pressed_tree;
2011 tree_view->priv->button_pressed_node->children->parent_node = tree_view->priv->button_pressed_node;
2012 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2014 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter))
2015 gtk_tree_view_build_tree (tree_view,
2016 tree_view->priv->button_pressed_node->children,
2018 gtk_tree_path_get_depth (path) + 1,
2020 GTK_WIDGET_REALIZED (widget));
2024 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
2025 tree_view->priv->button_pressed_node->children,
2026 tree_view->priv->button_pressed_node->children->root);
2027 gtk_tree_model_get_iter (tree_view->priv->model,
2031 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (widget),
2032 tree_view->priv->button_pressed_node->children,
2034 gtk_tree_path_get_depth (path));
2035 gtk_tree_view_unref_tree (GTK_TREE_VIEW (widget),
2036 tree_view->priv->button_pressed_node->children);
2037 _gtk_rbtree_remove (tree_view->priv->button_pressed_node->children);
2039 gtk_tree_path_free (path);
2041 _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2044 tree_view->priv->button_pressed_node = NULL;
2051 gtk_tree_view_set_focus_child (GtkContainer *container,
2057 gtk_tree_view_draw_focus (GtkWidget *widget)
2059 GtkTreeView *tree_view;
2060 GtkTreePath *cursor_path;
2061 GtkRBTree *tree = NULL;
2062 GtkRBNode *node = NULL;
2066 g_return_if_fail (widget != NULL);
2067 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2069 tree_view = GTK_TREE_VIEW (widget);
2071 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
2074 if (tree_view->priv->cursor == NULL)
2077 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2078 if (cursor_path == NULL)
2081 _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
2085 gtk_tree_path_free (cursor_path);
2089 gdk_drawable_get_size (tree_view->priv->bin_window,
2094 y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2095 gdk_drawable_get_size (tree_view->priv->bin_window,
2098 height = BACKGROUND_HEIGHT (node) - 1;
2099 if (tree_view->priv->focus_column != NULL)
2101 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data);
2105 g_object_get (G_OBJECT (column->cell),
2106 "can_activate", &can_focus,
2107 "visible", &visible,
2109 if (can_focus && visible)
2112 GdkRectangle cell_area;
2116 cell_area.x = column->button->allocation.x;
2118 cell_area.width = column->displayed_width;
2119 cell_area.height = CELL_HEIGHT (node);
2121 gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
2122 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, &iter);
2124 gtk_cell_renderer_get_size (column->cell, GTK_WIDGET (tree_view), &cell_area, &x_offset, &y_offset, &width, &height);
2127 x = cell_area.x + x_offset - 1;
2128 y = cell_area.y + y_offset - 1 + TREE_VIEW_VERTICAL_SEPARATOR/2;
2132 gtk_paint_focus (widget->style,
2133 tree_view->priv->bin_window,
2137 x, y, width, height);
2139 gtk_tree_path_free (cursor_path);
2144 gtk_tree_view_focus_in (GtkWidget *widget,
2145 GdkEventFocus *event)
2147 GtkTreeView *tree_view;
2149 g_return_val_if_fail (widget != NULL, FALSE);
2150 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2151 g_return_val_if_fail (event != NULL, FALSE);
2153 tree_view = GTK_TREE_VIEW (widget);
2155 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2157 /* FIXME don't redraw so much */
2158 gtk_widget_queue_draw (widget);
2165 gtk_tree_view_focus_out (GtkWidget *widget,
2166 GdkEventFocus *event)
2168 g_return_val_if_fail (widget != NULL, FALSE);
2169 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2170 g_return_val_if_fail (event != NULL, FALSE);
2172 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2174 /* FIXME don't redraw so much */
2175 gtk_widget_queue_draw (widget);
2180 /* Returns TRUE if the focus is within the headers, after the focus operation is
2184 gtk_tree_view_header_focus (GtkTreeView *tree_view,
2185 GtkDirectionType dir)
2187 GtkWidget *focus_child;
2188 GtkContainer *container;
2190 GList *last_column, *first_column;
2193 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2196 focus_child = GTK_CONTAINER (tree_view)->focus_child;
2197 container = GTK_CONTAINER (tree_view);
2199 for (last_column = g_list_last (tree_view->priv->columns);
2201 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2202 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2203 last_column = last_column->prev);
2205 for (first_column = tree_view->priv->columns;
2207 !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible) &&
2208 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button);
2209 first_column = first_column->next);
2211 /* No headers are visible, or are focusable. We can't focus in or out.
2213 if (last_column == NULL)
2218 case GTK_DIR_TAB_BACKWARD:
2219 case GTK_DIR_TAB_FORWARD:
2222 if (focus_child == NULL)
2224 if (tree_view->priv->focus_column != NULL)
2225 focus_child = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data)->button;
2227 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
2228 gtk_widget_grab_focus (focus_child);
2235 if (focus_child == NULL)
2237 if (tree_view->priv->focus_column != NULL)
2238 focus_child = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data)->button;
2239 else if (dir == GTK_DIR_LEFT)
2240 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
2242 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
2243 gtk_widget_grab_focus (focus_child);
2247 if (gtk_container_focus (GTK_CONTAINER (focus_child), dir))
2249 /* The focus moves inside the button. */
2250 /* This is probably a great example of bad UI */
2254 /* We need to move the focus among the row of buttons. */
2255 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2256 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
2259 if (tmp_list == first_column && dir == GTK_DIR_LEFT)
2261 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
2262 gtk_widget_grab_focus (focus_child);
2265 else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
2267 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
2268 gtk_widget_grab_focus (focus_child);
2274 GtkTreeViewColumn *column;
2276 if (dir == GTK_DIR_RIGHT)
2277 tmp_list = tmp_list->next;
2279 tmp_list = tmp_list->prev;
2281 if (tmp_list == NULL)
2283 g_warning ("Internal button not found");
2286 column = tmp_list->data;
2287 if (column->button &&
2289 GTK_WIDGET_CAN_FOCUS (column->button))
2291 focus_child = column->button;
2292 gtk_widget_grab_focus (column->button);
2298 g_assert_not_reached ();
2302 /* if focus child is non-null, we assume it's been set to the current focus child
2306 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2307 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
2310 tree_view->priv->focus_column = tmp_list;
2312 /* If the following isn't true, then the view is smaller then the scrollpane.
2314 if ((focus_child->allocation.x + focus_child->allocation.width) <=
2315 (tree_view->priv->hadjustment->upper))
2317 /* Scroll to the button, if needed */
2318 if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
2319 (focus_child->allocation.x + focus_child->allocation.width))
2320 gtk_adjustment_set_value (tree_view->priv->hadjustment,
2321 focus_child->allocation.x + focus_child->allocation.width -
2322 tree_view->priv->hadjustment->page_size);
2323 else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
2324 gtk_adjustment_set_value (tree_view->priv->hadjustment,
2325 focus_child->allocation.x);
2329 return (focus_child != NULL);
2332 /* WARNING: Somewhat scary function */
2333 /* We make the assumption that if container->focus_child != NULL, the focus must
2334 * be in the header. For now, this is accurate. It may not be in the future.
2337 gtk_tree_view_focus (GtkContainer *container,
2338 GtkDirectionType direction)
2340 GtkTreeView *tree_view;
2341 GtkWidget *focus_child;
2343 GtkRBTree *cursor_tree;
2344 GtkRBNode *cursor_node;
2345 GtkTreePath *cursor_path;
2347 g_return_val_if_fail (container != NULL, FALSE);
2348 g_return_val_if_fail (GTK_IS_TREE_VIEW (container), FALSE);
2349 g_return_val_if_fail (GTK_WIDGET_VISIBLE (container), FALSE);
2351 tree_view = GTK_TREE_VIEW (container);
2353 if (!GTK_WIDGET_IS_SENSITIVE (container))
2356 focus_child = container->focus_child;
2358 /* Case 1. Headers have focus. */
2365 return (gtk_tree_view_header_focus (tree_view, direction));
2366 case GTK_DIR_TAB_BACKWARD:
2369 case GTK_DIR_TAB_FORWARD:
2372 if (tree_view->priv->tree == NULL)
2375 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2376 gtk_widget_grab_focus (GTK_WIDGET (container));
2378 if (tree_view->priv->selection == NULL)
2379 tree_view->priv->selection =
2380 _gtk_tree_selection_new_with_tree_view (tree_view);
2382 /* if there is no keyboard focus yet, we select the first node
2387 if (tree_view->priv->cursor)
2388 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2390 if (cursor_path == NULL)
2392 GtkTreePath *tmp_path = gtk_tree_path_new_root ();
2394 if (tree_view->priv->cursor)
2395 gtk_tree_row_reference_free (tree_view->priv->cursor);
2397 tree_view->priv->cursor =
2398 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
2399 cursor_path = tmp_path;
2402 gtk_tree_selection_select_path (tree_view->priv->selection,
2405 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2407 gtk_tree_path_free (cursor_path);
2413 /* Case 2. We don't have focus at all. */
2414 if (!GTK_WIDGET_HAS_FOCUS (container))
2416 if ((direction == GTK_DIR_TAB_FORWARD) ||
2417 (direction == GTK_DIR_RIGHT) ||
2418 (direction == GTK_DIR_DOWN) ||
2419 (direction == GTK_DIR_LEFT) ||
2420 (tree_view->priv->tree == NULL))
2421 return gtk_tree_view_header_focus (tree_view, direction);
2423 /* The headers didn't want the focus, so we take it. */
2424 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2425 gtk_widget_grab_focus (GTK_WIDGET (container));
2427 if (tree_view->priv->selection == NULL)
2428 tree_view->priv->selection =
2429 _gtk_tree_selection_new_with_tree_view (tree_view);
2432 if (tree_view->priv->cursor)
2433 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2435 if (cursor_path == NULL)
2437 GtkTreePath *tmp_path = gtk_tree_path_new_root ();
2439 if (tree_view->priv->cursor)
2440 gtk_tree_row_reference_free (tree_view->priv->cursor);
2442 tree_view->priv->cursor =
2443 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
2444 cursor_path = tmp_path;
2447 gtk_tree_selection_select_path (tree_view->priv->selection,
2450 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2452 gtk_tree_path_free (cursor_path);
2457 /* Case 3. We have focus already. */
2458 if (tree_view->priv->tree == NULL)
2461 if (direction == GTK_DIR_TAB_BACKWARD)
2462 return (gtk_tree_view_header_focus (tree_view, direction));
2463 else if (direction == GTK_DIR_TAB_FORWARD)
2467 if (tree_view->priv->cursor)
2468 cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2470 /* Do we have a focus path? We should, unless it was deleted. */
2471 /* in that case, we pick the first one arbitrarily */
2472 if (cursor_path == NULL)
2474 GtkTreePath *tmp_path = gtk_tree_path_new_root ();
2476 if (tree_view->priv->cursor)
2477 gtk_tree_row_reference_free (tree_view->priv->cursor);
2479 tree_view->priv->cursor =
2480 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
2481 cursor_path = tmp_path;
2483 gtk_tree_selection_select_path (tree_view->priv->selection,
2486 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2488 gtk_tree_path_free (cursor_path);
2493 /* Case 4. We have focus already. Move the cursor. */
2494 if (direction == GTK_DIR_LEFT)
2497 val = tree_view->priv->hadjustment->value - tree_view->priv->hadjustment->page_size/2;
2498 val = MAX (val, 0.0);
2499 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
2500 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2502 gtk_tree_path_free (cursor_path);
2506 if (direction == GTK_DIR_RIGHT)
2509 val = tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size/2;
2510 val = MIN (tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size, val);
2511 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
2512 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2514 gtk_tree_path_free (cursor_path);
2522 _gtk_tree_view_find_node (tree_view, cursor_path,
2526 /* undraw the old row */
2527 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2529 gtk_tree_path_free (cursor_path);
2532 if (tree_view->priv->cursor)
2534 gtk_tree_row_reference_free (tree_view->priv->cursor);
2535 tree_view->priv->cursor = NULL;
2540 case GTK_DIR_TAB_BACKWARD:
2542 _gtk_rbtree_prev_full (cursor_tree,
2547 case GTK_DIR_TAB_FORWARD:
2549 _gtk_rbtree_next_full (cursor_tree,
2560 GdkModifierType state = 0;
2562 event = gtk_get_current_event ();
2564 gdk_event_get_state (event, &state);
2567 gdk_event_free (event);
2569 cursor_path = _gtk_tree_view_find_path (tree_view,
2575 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
2581 tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
2584 /* draw the newly-selected row */
2585 gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
2587 gtk_tree_path_free (cursor_path);
2590 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
2591 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2596 /* At this point, we've progressed beyond the edge of the rows. */
2598 if (direction == GTK_DIR_UP)
2599 /* We can't go back anymore. Try the headers */
2600 return (gtk_tree_view_header_focus (tree_view, direction));
2602 /* we've reached the end of the tree. Go on. */
2609 gtk_tree_view_remove (GtkContainer *container,
2612 GtkTreeView *tree_view;
2613 GtkTreeViewChild *child = NULL;
2616 g_return_if_fail (container != NULL);
2617 g_return_if_fail (GTK_IS_TREE_VIEW (container));
2619 tree_view = GTK_TREE_VIEW (container);
2621 tmp_list = tree_view->priv->children;
2624 child = tmp_list->data;
2625 if (child->widget == widget)
2627 gtk_widget_unparent (widget);
2629 tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
2630 g_list_free_1 (tmp_list);
2635 tmp_list = tmp_list->next;
2638 tmp_list = tree_view->priv->columns;
2642 GtkTreeViewColumn *column;
2643 column = tmp_list->data;
2644 if (column->button == widget)
2646 gtk_widget_unparent (widget);
2649 tmp_list = tmp_list->next;
2655 gtk_tree_view_forall (GtkContainer *container,
2656 gboolean include_internals,
2657 GtkCallback callback,
2658 gpointer callback_data)
2660 GtkTreeView *tree_view;
2661 GtkTreeViewChild *child = NULL;
2662 GtkTreeViewColumn *column;
2665 g_return_if_fail (container != NULL);
2666 g_return_if_fail (GTK_IS_TREE_VIEW (container));
2667 g_return_if_fail (callback != NULL);
2669 tree_view = GTK_TREE_VIEW (container);
2671 tmp_list = tree_view->priv->children;
2674 child = tmp_list->data;
2675 tmp_list = tmp_list->next;
2677 (* callback) (child->widget, callback_data);
2679 if (include_internals == FALSE)
2682 for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2684 column = tmp_list->data;
2687 (* callback) (column->button, callback_data);
2692 gtk_tree_view_row_activated (GtkTreeView *tree_view,
2693 GtkTreeViewColumn *column)
2695 g_return_if_fail (tree_view != NULL);
2696 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2698 g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, column);
2701 /* TreeModel Callbacks
2705 gtk_tree_view_changed (GtkTreeModel *model,
2710 GtkTreeView *tree_view = (GtkTreeView *)data;
2714 gboolean dirty_marked;
2715 gboolean free_path = FALSE;
2717 g_return_if_fail (path != NULL || iter != NULL);
2721 path = gtk_tree_model_get_path (model, iter);
2724 else if (iter == NULL)
2725 gtk_tree_model_get_iter (model, iter, path);
2727 if (_gtk_tree_view_find_node (tree_view,
2731 /* We aren't actually showing the node */
2737 dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
2739 gtk_tree_path_get_depth (path),
2742 if (GTK_RBNODE_GET_HEIGHT (node) != height + TREE_VIEW_VERTICAL_SEPARATOR)
2744 _gtk_rbtree_node_set_height (tree, node, height + TREE_VIEW_VERTICAL_SEPARATOR);
2745 gtk_widget_queue_resize (GTK_WIDGET (data));
2749 gtk_widget_queue_resize (GTK_WIDGET (data));
2752 gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
2757 gtk_tree_path_free (path);
2761 gtk_tree_view_inserted (GtkTreeModel *model,
2766 GtkTreeView *tree_view = (GtkTreeView *) data;
2768 GtkRBTree *tmptree, *tree;
2769 GtkRBNode *tmpnode = NULL;
2773 gboolean free_path = FALSE;
2775 if (tree_view->priv->tree == NULL)
2776 tree_view->priv->tree = _gtk_rbtree_new ();
2778 tmptree = tree = tree_view->priv->tree;
2779 g_return_if_fail (path != NULL || iter != NULL);
2783 path = gtk_tree_model_get_path (model, iter);
2786 else if (iter == NULL)
2787 gtk_tree_model_get_iter (model, iter, path);
2789 /* Update all row-references */
2790 gtk_tree_row_reference_inserted (G_OBJECT (data), path);
2792 depth = gtk_tree_path_get_depth (path);
2793 indices = gtk_tree_path_get_indices (path);
2795 /* First, find the parent tree */
2796 while (i < depth - 1)
2798 if (tmptree == NULL)
2800 /* We aren't showing the node */
2804 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
2805 if (tmpnode == NULL)
2807 g_warning ("A node was inserted with a parent that's not in the tree.\n" \
2808 "This possibly means that a GtkTreeModel inserted a child node\n" \
2809 "before the parent was inserted.");
2812 else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
2814 /* FIXME enforce correct behavior on model, probably */
2815 /* In theory, the model should have emitted has_child_toggled here. We
2816 * try to catch it anyway, just to be safe, in case the model hasn't.
2818 GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
2821 gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
2822 gtk_tree_path_free (tmppath);
2826 tmptree = tmpnode->children;
2835 gtk_tree_model_ref_node (tree_view->priv->model, iter);
2836 max_height = gtk_tree_view_insert_iter_height (tree_view,
2840 if (indices[depth - 1] == 0)
2842 tmpnode = _gtk_rbtree_find_count (tree, 1);
2843 _gtk_rbtree_insert_before (tree, tmpnode, max_height);
2847 tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
2848 _gtk_rbtree_insert_after (tree, tmpnode, max_height);
2851 _gtk_tree_view_update_size (tree_view);
2855 gtk_tree_path_free (path);
2859 gtk_tree_view_has_child_toggled (GtkTreeModel *model,
2864 GtkTreeView *tree_view = (GtkTreeView *)data;
2865 GtkTreeIter real_iter;
2869 gboolean free_path = FALSE;
2871 g_return_if_fail (path != NULL || iter != NULL);
2878 path = gtk_tree_model_get_path (model, iter);
2881 else if (iter == NULL)
2882 gtk_tree_model_get_iter (model, &real_iter, path);
2884 if (_gtk_tree_view_find_node (tree_view,
2888 /* We aren't actually showing the node */
2894 has_child = gtk_tree_model_iter_has_child (model, &real_iter);
2897 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
2901 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
2903 GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
2905 if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
2907 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2908 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
2912 for (list = tree_view->priv->columns; list; list = list->next)
2913 if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
2915 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
2919 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
2923 /* FIXME: Just redraw the node */
2924 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2929 gtk_tree_path_free (path);
2933 gtk_tree_view_deleted (GtkTreeModel *model,
2937 GtkTreeView *tree_view = (GtkTreeView *)data;
2942 g_return_if_fail (path != NULL);
2944 if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
2950 gtk_tree_row_reference_deleted (G_OBJECT (data), path);
2952 /* next, update the selection */
2953 if (tree_view->priv->anchor)
2955 GtkTreePath *anchor_path;
2957 /* the row reference may not have been updated yet. If it has not,
2958 * then anchor_path and path being equal indicates that the anchor
2959 * row was deleted. If it has, then anchor_path == NULL indicates the
2960 * the anchor row was deleted.
2963 anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2965 if (anchor_path == NULL ||
2966 gtk_tree_path_compare (path, anchor_path) == 0)
2968 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) &&
2969 tree_view->priv->selection)
2970 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->selection),
2971 "selection_changed");
2975 gtk_tree_path_free (anchor_path);
2978 for (list = tree_view->priv->columns; list; list = list->next)
2979 if (((GtkTreeViewColumn *)list->data)->visible &&
2980 ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2981 ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
2983 /* Ensure we don't have a dangling pointer to a dead node */
2984 ensure_unprelighted (tree_view);
2986 g_assert (tree_view->priv->prelight_node == NULL);
2988 if (tree->root->count == 1)
2990 if (tree_view->priv->tree == tree)
2991 tree_view->priv->tree = NULL;
2993 _gtk_rbtree_remove (tree);
2997 _gtk_rbtree_remove_node (tree, node);
3000 _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
3003 /* Internal tree functions */
3005 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
3010 GtkTreeViewColumn *column;
3011 GtkCellRenderer *cell;
3013 gint max_height = 0;
3018 /* do stuff with node */
3019 for (list = tree_view->priv->columns; list; list = list->next)
3021 gint height = 0, width = 0;
3022 column = list->data;
3024 if (!column->visible)
3027 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
3033 cell = column->cell;
3034 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
3036 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, &height);
3037 max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPARATOR + height);
3039 if (i == tree_view->priv->expander_column &&
3040 TREE_VIEW_DRAW_EXPANDERS (tree_view))
3041 gtk_tree_view_column_set_width (column,
3042 MAX (column->width, depth * tree_view->priv->tab_offset + width));
3044 gtk_tree_view_column_set_width (column,
3045 MAX (column->width, width));
3053 gtk_tree_view_build_tree (GtkTreeView *tree_view,
3058 gboolean calc_bounds)
3060 GtkRBNode *temp = NULL;
3067 max_height = gtk_tree_view_insert_iter_height (tree_view,
3072 gtk_tree_model_ref_node (tree_view->priv->model, iter);
3073 temp = _gtk_rbtree_insert_after (tree, temp, max_height);
3078 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
3080 temp->children = _gtk_rbtree_new ();
3081 temp->children->parent_tree = tree;
3082 temp->children->parent_node = temp;
3083 gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
3086 if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
3088 if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
3089 temp->flags ^= GTK_RBNODE_IS_PARENT;
3090 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
3093 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
3097 gtk_tree_view_calc_size (GtkTreeView *tree_view,
3104 GtkCellRenderer *cell;
3106 GtkTreeViewColumn *column;
3110 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
3113 while (temp->left != tree->nil)
3119 /* Do stuff with node */
3120 for (list = tree_view->priv->columns, i = 0; i < tree_view->priv->n_columns; list = list->next, i++)
3122 gint height = 0, width = 0;
3123 column = list->data;
3125 if (!column->visible)
3128 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
3129 cell = column->cell;
3130 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, &height);
3131 max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPARATOR + height);
3133 /* FIXME: I'm getting the width of all nodes here. )-: */
3134 if (column->dirty == FALSE)
3137 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
3141 if (i == tree_view->priv->expander_column &&
3142 TREE_VIEW_DRAW_EXPANDERS (tree_view))
3143 gtk_tree_view_column_set_width (column,
3144 MAX (column->width, depth * tree_view->priv->tab_offset + width));
3146 gtk_tree_view_column_set_width (column, MAX (column->width, width));
3148 _gtk_rbtree_node_set_height (tree, temp, max_height);
3149 if (temp->children != NULL &&
3150 gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
3151 gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
3152 temp = _gtk_rbtree_next (tree, temp);
3154 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
3158 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
3163 GtkCellRenderer *cell;
3164 GtkTreeViewColumn *column;
3167 gint retval = FALSE;
3173 for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3176 column = list->data;
3177 if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
3179 if (!column->visible)
3182 cell = column->cell;
3183 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, iter);
3187 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, &tmpheight);
3188 *height = MAX (*height, tmpheight);
3192 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), NULL, NULL, NULL, &width, NULL);
3194 if (i == tree_view->priv->expander_column &&
3195 TREE_VIEW_DRAW_EXPANDERS (tree_view))
3197 if (depth * tree_view->priv->tab_offset + width > column->width)
3199 column->dirty = TRUE;
3205 if (width > column->width)
3207 column->dirty = TRUE;
3217 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
3222 GtkRBNode *temp = tree->root;
3223 GtkTreeViewColumn *column;
3226 gboolean is_all_dirty;
3228 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
3230 while (temp->left != tree->nil)
3235 is_all_dirty = TRUE;
3236 for (list = tree_view->priv->columns; list; list = list->next)
3238 column = list->data;
3239 if (column->dirty == FALSE)
3241 is_all_dirty = FALSE;
3249 gtk_tree_view_discover_dirty_iter (tree_view,
3253 if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
3254 temp->children != NULL)
3255 gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
3256 temp = _gtk_rbtree_next (tree, temp);
3258 while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
3263 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
3266 gboolean dirty = FALSE;
3268 GtkTreeViewColumn *column;
3271 if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
3272 tree_view->priv->model)
3273 gtk_tree_view_setup_model (tree_view);
3275 for (list = tree_view->priv->columns; list; list = list->next)
3277 column = list->data;
3281 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3286 w = MAX (w, column->button->requisition.width);
3288 gtk_tree_view_column_set_width (column, w);
3296 if (tree_view->priv->model == NULL)
3299 path = gtk_tree_path_new_root ();
3300 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
3302 gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
3303 _gtk_tree_view_update_size (tree_view);
3306 gtk_tree_path_free (path);
3308 for (list = tree_view->priv->columns; list; list = list->next)
3310 column = list->data;
3311 column->dirty = FALSE;
3316 gtk_tree_view_create_buttons (GtkTreeView *tree_view)
3318 GtkWidget *alignment;
3321 GtkTreeViewColumn *column;
3326 /* FIXME this has to be merged with update_button_contents() in
3327 * gtktreeviewcolumn.c
3330 for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
3332 column = list->data;
3334 if (column->button != NULL)
3337 gtk_tree_view_create_button (tree_view, i);
3338 alignment = gtk_alignment_new (column->xalign, 0.5, 0.0, 0.0);
3340 hbox = gtk_hbox_new (FALSE, 2);
3341 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
3343 column->arrow = arrow;
3344 column->alignment = alignment;
3347 label = column->child;
3350 label = gtk_label_new (column->title);
3351 gtk_widget_show (label);
3354 if (column->xalign <= 0.5)
3355 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
3357 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
3359 gtk_box_pack_start (GTK_BOX (hbox), alignment, TRUE, TRUE, 0);
3361 gtk_container_add (GTK_CONTAINER (alignment), label);
3362 gtk_container_add (GTK_CONTAINER (column->button), hbox);
3364 gtk_widget_show (hbox);
3365 gtk_widget_show (alignment);
3366 /* don't show the arrow yet */
3369 gtk_tree_view_size_request_buttons (tree_view);
3371 if (GTK_WIDGET_REALIZED (tree_view))
3372 gtk_tree_view_realize_buttons (tree_view);
3374 if (GTK_WIDGET_MAPPED (tree_view))
3375 gtk_tree_view_map_buttons (tree_view);
3379 /* Make sure the node is visible vertically */
3381 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
3387 offset = _gtk_rbtree_node_find_offset (tree, node);
3389 /* we reverse the order, b/c in the unusual case of the
3390 * node's height being taller then the visible area, we'd rather
3391 * have the node flush to the top
3393 if (offset + GTK_RBNODE_GET_HEIGHT (node) >
3394 tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
3395 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
3396 offset + GTK_RBNODE_GET_HEIGHT (node) -
3397 tree_view->priv->vadjustment->page_size);
3398 if (offset < tree_view->priv->vadjustment->value)
3399 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
3403 /* This function could be more efficient.
3404 * I'll optimize it if profiling seems to imply that
3408 _gtk_tree_view_find_path (GtkTreeView *tree_view,
3413 GtkRBTree *tmp_tree;
3414 GtkRBNode *tmp_node, *last;
3417 path = gtk_tree_path_new ();
3419 g_return_val_if_fail (node != NULL, path);
3420 g_return_val_if_fail (node != tree->nil, path);
3422 count = 1 + node->left->count;
3425 tmp_node = node->parent;
3429 while (tmp_node != tmp_tree->nil)
3431 if (tmp_node->right == last)
3432 count += 1 + tmp_node->left->count;
3434 tmp_node = tmp_node->parent;
3436 gtk_tree_path_prepend_index (path, count - 1);
3437 last = tmp_tree->parent_node;
3438 tmp_tree = tmp_tree->parent_tree;
3441 count = 1 + last->left->count;
3442 tmp_node = last->parent;
3448 /* Returns TRUE if we ran out of tree before finding the node,
3449 * so the returned node is the last node we saw and the returned
3453 _gtk_tree_view_find_node (GtkTreeView *tree_view,
3458 GtkRBNode *tmpnode = NULL;
3459 GtkRBTree *tmptree = tree_view->priv->tree;
3460 gint *indices = gtk_tree_path_get_indices (path);
3461 gint depth = gtk_tree_path_get_depth (path);
3469 if (tmptree == NULL)
3475 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
3483 tmptree = tmpnode->children;
3489 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
3496 g_return_if_fail (node != NULL);
3501 GtkRBTree *new_tree;
3502 GtkRBNode *new_node;
3504 new_tree = node->children;
3505 new_node = new_tree->root;
3507 while (new_node && new_node->left != new_tree->nil)
3508 new_node = new_node->left;
3510 g_return_if_fail (gtk_tree_model_iter_children (model, &child, iter));
3511 gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
3514 gtk_tree_model_unref_node (model, iter);
3515 node = _gtk_rbtree_next (tree, node);
3517 while (gtk_tree_model_iter_next (model, iter));
3521 gtk_tree_view_unref_tree (GtkTreeView *tree_view,
3529 while (node && node->left != tree->nil)
3532 g_return_if_fail (node != NULL);
3533 path = _gtk_tree_view_find_path (tree_view, tree, node);
3534 gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
3536 gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
3537 gtk_tree_path_free (path);
3541 gtk_tree_view_queue_draw_node (GtkTreeView *tree_view,
3544 GdkRectangle *clip_rect)
3548 if (!GTK_WIDGET_REALIZED (tree_view))
3552 rect.width = tree_view->priv->width;
3554 rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3555 rect.height = BACKGROUND_HEIGHT (node);
3559 GdkRectangle new_rect;
3561 gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
3563 gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
3567 gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
3572 gtk_tree_view_queue_draw_path (GtkTreeView *tree_view,
3574 GdkRectangle *clip_rect)
3576 GtkRBTree *tree = NULL;
3577 GtkRBNode *node = NULL;
3579 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3582 gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
3585 /* x and y are the mouse position
3588 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
3599 if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
3602 widget = GTK_WIDGET (tree_view);
3604 gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
3607 area.y = CELL_FIRST_PIXEL (tree_view, tree, node);
3608 area.width = tree_view->priv->tab_offset - 2;
3609 area.height = CELL_HEIGHT (node);
3611 if (node == tree_view->priv->button_pressed_node)
3613 if (x >= area.x && x <= (area.x + area.width) &&
3614 y >= area.y && y <= (area.y + area.height))
3615 state = GTK_STATE_ACTIVE;
3617 state = GTK_STATE_NORMAL;
3621 if (node == tree_view->priv->prelight_node &&
3622 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3623 state = GTK_STATE_PRELIGHT;
3625 state = GTK_STATE_NORMAL;
3628 /* FIXME expander size should come from a style property */
3629 #define EXPANDER_SIZE 8
3630 gtk_paint_expander (widget->style,
3631 tree_view->priv->bin_window,
3637 (area.y + (area.height - EXPANDER_SIZE) / 2 - (area.height + 1) % 2),
3638 node->children != NULL);
3639 #undef EXPANDER_SIZE
3644 _gtk_tree_view_update_col_width (GtkTreeView *tree_view)
3646 GList *list, *last_column;
3647 GtkTreeViewColumn *column;
3650 for (last_column = g_list_last (tree_view->priv->columns);
3652 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
3653 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
3654 last_column = last_column->prev)
3657 if (last_column == NULL)
3660 for (list = tree_view->priv->columns; list != last_column; list = list->next)
3662 column = GTK_TREE_VIEW_COLUMN (list->data);
3663 if (! column->visible)
3666 width += column->width;
3667 column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
3669 column = GTK_TREE_VIEW_COLUMN (last_column->data);
3670 column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
3674 _gtk_tree_view_update_size (GtkTreeView *tree_view)
3678 GtkTreeViewColumn *column;
3681 if (tree_view->priv->model == NULL)
3683 tree_view->priv->width = 0;
3684 tree_view->priv->height = 0;
3685 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3690 for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
3692 column = list->data;
3693 if (!column->visible)
3695 width += TREE_VIEW_COLUMN_WIDTH (column);
3698 if (tree_view->priv->tree == NULL)
3701 height = tree_view->priv->tree->root->offset + TREE_VIEW_VERTICAL_SEPARATOR;
3703 if (tree_view->priv->width != width)
3705 tree_view->priv->width = width;
3706 tree_view->priv->hadjustment->upper = width;
3707 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
3710 if (tree_view->priv->height != height)
3712 tree_view->priv->height = height;
3713 tree_view->priv->vadjustment->upper = tree_view->priv->height;
3714 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
3717 if (GTK_WIDGET_REALIZED (tree_view))
3719 gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
3720 gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
3722 _gtk_tree_view_update_col_width (tree_view);
3725 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3728 /* this function returns the new width of the column being resized given
3729 * the column and x position of the cursor; the x cursor position is passed
3730 * in as a pointer and automagicly corrected if it's beyond min/max limits
3733 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
3737 GtkTreeViewColumn *column;
3740 /* first translate the x position from widget->window
3741 * to clist->clist_window
3744 column = g_list_nth (tree_view->priv->columns, i)->data;
3745 width = *x - column->button->allocation.x;
3747 /* Clamp down the value */
3748 if (column->min_width == -1)
3749 width = MAX (column->button->requisition.width,
3752 width = MAX (column->min_width,
3754 if (column->max_width != -1)
3755 width = MIN (width, column->max_width != -1);
3756 *x = column->button->allocation.x + width;
3763 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
3764 GtkTreeView *tree_view)
3766 if (GTK_WIDGET_REALIZED (tree_view))
3768 gdk_window_move (tree_view->priv->bin_window,
3769 - tree_view->priv->hadjustment->value,
3770 - tree_view->priv->vadjustment->value);
3771 gdk_window_move (tree_view->priv->header_window,
3772 - tree_view->priv->hadjustment->value,
3775 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
3776 gdk_window_process_updates (tree_view->priv->header_window, TRUE);
3786 * gtk_tree_view_new:
3788 * Creates a new #GtkTreeView widget.
3790 * Return value: A newly created #GtkTreeView widget.
3793 gtk_tree_view_new (void)
3795 GtkTreeView *tree_view;
3797 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
3799 return GTK_WIDGET (tree_view);
3803 * gtk_tree_view_new_with_model:
3804 * @model: the model.
3806 * Creates a new #GtkTreeView widget with the model initialized to @model.
3808 * Return value: A newly created #GtkTreeView widget.
3811 gtk_tree_view_new_with_model (GtkTreeModel *model)
3813 GtkTreeView *tree_view;
3815 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
3816 gtk_tree_view_set_model (tree_view, model);
3818 return GTK_WIDGET (tree_view);
3822 * gtk_tree_view_get_model:
3823 * @tree_view: a #GtkTreeView
3825 * Returns the model the the #GtkTreeView is based on. Returns NULL if the
3828 * Return value: A #GtkTreeModel, or NULL if none is currently being used.
3831 gtk_tree_view_get_model (GtkTreeView *tree_view)
3833 g_return_val_if_fail (tree_view != NULL, NULL);
3834 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3836 return tree_view->priv->model;
3840 gtk_tree_view_setup_model (GtkTreeView *tree_view)
3845 tree_view->priv->tree = NULL;
3847 g_signal_connectc (tree_view->priv->model,
3849 gtk_tree_view_changed,
3852 g_signal_connectc (tree_view->priv->model,
3854 gtk_tree_view_inserted,
3857 g_signal_connectc (tree_view->priv->model,
3858 "has_child_toggled",
3859 gtk_tree_view_has_child_toggled,
3862 g_signal_connectc (tree_view->priv->model,
3864 gtk_tree_view_deleted,
3868 if (tree_view->priv->columns == NULL)
3871 path = gtk_tree_path_new_root ();
3873 if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
3875 tree_view->priv->tree = _gtk_rbtree_new ();
3876 gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
3879 gtk_tree_path_free (path);
3881 // gtk_tree_view_create_buttons (tree_view);
3883 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3887 * gtk_tree_view_set_model:
3888 * @tree_view: A #GtkTreeNode.
3889 * @model: The model.
3891 * Sets the model for a #GtkTreeView. If the @tree_view already has a model
3892 * set, it will remove it before setting the new model. If @model is NULL, then
3893 * it will unset the old model.
3896 gtk_tree_view_set_model (GtkTreeView *tree_view,
3897 GtkTreeModel *model)
3899 g_return_if_fail (tree_view != NULL);
3900 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3903 g_object_ref (model);
3905 if (tree_view->priv->model != NULL)
3907 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
3909 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3910 G_SIGNAL_MATCH_FUNC,
3912 gtk_tree_view_changed, NULL);
3913 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3914 G_SIGNAL_MATCH_FUNC,
3916 gtk_tree_view_inserted, NULL);
3917 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3918 G_SIGNAL_MATCH_FUNC,
3920 gtk_tree_view_has_child_toggled, NULL);
3921 g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
3922 G_SIGNAL_MATCH_FUNC,
3924 gtk_tree_view_deleted, NULL);
3925 _gtk_rbtree_free (tree_view->priv->tree);
3928 if (tree_view->priv->drag_dest_row)
3929 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
3931 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3932 g_object_unref (tree_view->priv->model);
3935 tree_view->priv->model = model;
3939 tree_view->priv->tree = NULL;
3940 if (GTK_WIDGET_REALIZED (tree_view))
3941 _gtk_tree_view_update_size (tree_view);
3944 else if (GTK_WIDGET_REALIZED (tree_view))
3946 gtk_tree_view_setup_model (tree_view);
3947 _gtk_tree_view_update_size (tree_view);
3950 g_object_notify (G_OBJECT (tree_view), "model");
3954 * gtk_tree_view_get_selection:
3955 * @tree_view: A #GtkTreeView.
3957 * Gets the #GtkTreeSelection associated with @tree_view.
3959 * Return value: A #GtkTreeSelection object.
3962 gtk_tree_view_get_selection (GtkTreeView *tree_view)
3964 g_return_val_if_fail (tree_view != NULL, NULL);
3965 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3967 if (tree_view->priv->selection == NULL)
3968 tree_view->priv->selection =
3969 _gtk_tree_selection_new_with_tree_view (tree_view);
3971 return tree_view->priv->selection;
3975 * gtk_tree_view_get_hadjustment:
3976 * @tree_view: A #GtkTreeView
3978 * Gets the #GtkAdjustment currently being used for the horizontal aspect.
3980 * Return value: A #GtkAdjustment object, or NULL if none is currently being
3984 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
3986 g_return_val_if_fail (tree_view != NULL, NULL);
3987 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3989 if (tree_view->priv->hadjustment == NULL)
3990 gtk_tree_view_set_hadjustment (tree_view, NULL);
3992 return tree_view->priv->hadjustment;
3996 * gtk_tree_view_set_hadjustment:
3997 * @tree_view: A #GtkTreeView
3998 * @adjustment: The #GtkAdjustment to set, or NULL
4000 * Sets the #GtkAdjustment for the current horizontal aspect.
4003 gtk_tree_view_set_hadjustment (GtkTreeView *tree_view,
4004 GtkAdjustment *adjustment)
4006 g_return_if_fail (tree_view != NULL);
4007 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4009 gtk_tree_view_set_adjustments (tree_view,
4011 tree_view->priv->vadjustment);
4013 g_object_notify (G_OBJECT (tree_view), "hadjustment");
4017 * gtk_tree_view_get_vadjustment:
4018 * @tree_view: A #GtkTreeView
4020 * Gets the #GtkAdjustment currently being used for the vertical aspect.
4022 * Return value: A #GtkAdjustment object, or NULL if none is currently being
4026 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
4028 g_return_val_if_fail (tree_view != NULL, NULL);
4029 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
4031 if (tree_view->priv->vadjustment == NULL)
4032 gtk_tree_view_set_vadjustment (tree_view, NULL);
4034 return tree_view->priv->vadjustment;
4038 * gtk_tree_view_set_vadjustment:
4039 * @tree_view: A #GtkTreeView
4040 * @adjustment: The #GtkAdjustment to set, or NULL
4042 * Sets the #GtkAdjustment for the current vertical aspect.
4045 gtk_tree_view_set_vadjustment (GtkTreeView *tree_view,
4046 GtkAdjustment *adjustment)
4048 g_return_if_fail (tree_view != NULL);
4049 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4051 gtk_tree_view_set_adjustments (tree_view,
4052 tree_view->priv->hadjustment,
4055 g_object_notify (G_OBJECT (tree_view), "vadjustment");
4059 * gtk_tree_view_set_adjustments:
4060 * @tree_view: A #GtkTreeView
4061 * @hadj: The horizontal #GtkAdjustment to set, or NULL
4062 * @vadj: The vertical #GtkAdjustment to set, or NULL
4064 * Sets the horizonal and or vertical #GtkAdjustment.
4067 gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
4068 GtkAdjustment *hadj,
4069 GtkAdjustment *vadj)
4071 gboolean need_adjust = FALSE;
4073 g_return_if_fail (tree_view != NULL);
4074 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4077 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4079 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4081 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4083 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4085 if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4087 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4088 gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4091 if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4093 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4094 gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4097 if (tree_view->priv->hadjustment != hadj)
4099 tree_view->priv->hadjustment = hadj;
4100 gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4101 gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4103 gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4104 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4109 if (tree_view->priv->vadjustment != vadj)
4111 tree_view->priv->vadjustment = vadj;
4112 gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4113 gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4115 gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4116 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4122 gtk_tree_view_adjustment_changed (NULL, tree_view);
4126 /* Column and header operations */
4129 * gtk_tree_view_get_headers_visible:
4130 * @tree_view: A #GtkTreeView.
4132 * Returns TRUE if the headers on the @tree_view are visible.
4134 * Return value: Whether the headers are visible or not.
4137 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
4139 g_return_val_if_fail (tree_view != NULL, FALSE);
4140 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
4142 return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
4146 * gtk_tree_view_set_headers_visible:
4147 * @tree_view: A #GtkTreeView.
4148 * @headers_visible: TRUE if the headers are visible
4150 * Sets the the visibility state of the headers.
4153 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
4154 gboolean headers_visible)
4158 GtkTreeViewColumn *column;
4160 g_return_if_fail (tree_view != NULL);
4161 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4163 headers_visible = !! headers_visible;
4165 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
4168 if (headers_visible)
4169 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
4171 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
4173 if (GTK_WIDGET_REALIZED (tree_view))
4175 gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
4176 if (headers_visible)
4178 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));
4180 if (GTK_WIDGET_MAPPED (tree_view))
4181 gtk_tree_view_map_buttons (tree_view);
4185 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
4187 for (list = tree_view->priv->columns; list; list = list->next)
4189 column = list->data;
4190 gtk_widget_unmap (column->button);
4192 gdk_window_hide (tree_view->priv->header_window);
4196 tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
4197 tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
4198 tree_view->priv->vadjustment->lower = 0;
4199 tree_view->priv->vadjustment->upper = tree_view->priv->height;
4200 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
4202 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4204 g_object_notify (G_OBJECT (tree_view), "headers_visible");
4209 * gtk_tree_view_columns_autosize:
4210 * @tree_view: A #GtkTreeView.
4212 * Resizes all columns to their optimal width.
4215 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
4217 gboolean dirty = FALSE;
4219 GtkTreeViewColumn *column;
4221 g_return_if_fail (tree_view != NULL);
4222 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4224 for (list = tree_view->priv->columns; list; list = list->next)
4226 column = list->data;
4227 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4229 column->dirty = TRUE;
4234 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4238 * gtk_tree_view_set_headers_clickable:
4239 * @tree_view: A #GtkTreeView.
4240 * @setting: TRUE if the columns are clickable.
4242 * Allow the column title buttons to be clicked.
4245 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
4250 g_return_if_fail (tree_view != NULL);
4251 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4252 g_return_if_fail (tree_view->priv->model != NULL);
4254 for (list = tree_view->priv->columns; list; list = list->next)
4255 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
4257 g_object_notify (G_OBJECT (tree_view), "headers_clickable");
4261 * gtk_tree_view_append_column:
4262 * @tree_view: A #GtkTreeView.
4263 * @column: The #GtkTreeViewColumn to add.
4265 * Appends @column to the list of columns.
4267 * Return value: The number of columns in @tree_view after appending.
4270 gtk_tree_view_append_column (GtkTreeView *tree_view,
4271 GtkTreeViewColumn *column)
4273 g_return_val_if_fail (tree_view != NULL, -1);
4274 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4275 g_return_val_if_fail (column != NULL, -1);
4276 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
4277 g_return_val_if_fail (column->tree_view == NULL, -1);
4279 return gtk_tree_view_insert_column (tree_view, column, -1);
4284 * gtk_tree_view_remove_column:
4285 * @tree_view: A #GtkTreeView.
4286 * @column: The #GtkTreeViewColumn to remove.
4288 * Removes @column from @tree_view.
4290 * Return value: The number of columns in @tree_view after removing.
4293 gtk_tree_view_remove_column (GtkTreeView *tree_view,
4294 GtkTreeViewColumn *column)
4296 g_return_val_if_fail (tree_view != NULL, -1);
4297 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4298 g_return_val_if_fail (column != NULL, -1);
4299 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
4300 g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
4302 _gtk_tree_view_column_unset_tree_view (column);
4304 if (tree_view->priv->focus_column &&
4305 GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data) == column)
4306 tree_view->priv->focus_column = NULL;
4308 tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
4310 g_object_unref (G_OBJECT (column));
4312 tree_view->priv->n_columns--;
4314 if (GTK_WIDGET_REALIZED (tree_view))
4318 for (list = tree_view->priv->columns; list; list = list->next)
4320 column = GTK_TREE_VIEW_COLUMN (list->data);
4321 if (column->visible)
4322 column->dirty = TRUE;
4325 if (tree_view->priv->n_columns == 0 &&
4326 gtk_tree_view_get_headers_visible (tree_view))
4327 gdk_window_hide (tree_view->priv->header_window);
4329 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4333 return tree_view->priv->n_columns;
4337 * gtk_tree_view_insert_column:
4338 * @tree_view: A #GtkTreeView.
4339 * @column: The #GtkTreeViewColumn to be inserted.
4340 * @position: The position to insert @column in.
4342 * This inserts the @column into the @tree_view at @position. If @position is
4343 * -1, then the column is inserted at the end.
4345 * Return value: The number of columns in @tree_view after insertion.
4348 gtk_tree_view_insert_column (GtkTreeView *tree_view,
4349 GtkTreeViewColumn *column,
4352 g_return_val_if_fail (tree_view != NULL, -1);
4353 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4354 g_return_val_if_fail (column != NULL, -1);
4355 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
4356 g_return_val_if_fail (column->tree_view == NULL, -1);
4358 g_object_ref (G_OBJECT (column));
4360 if (tree_view->priv->n_columns == 0 &&
4361 GTK_WIDGET_REALIZED (tree_view) &&
4362 gtk_tree_view_get_headers_visible (tree_view))
4364 gdk_window_show (tree_view->priv->header_window);
4367 tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
4369 _gtk_tree_view_column_set_tree_view (column, tree_view);
4370 _gtk_tree_view_column_create_button (column);
4372 tree_view->priv->n_columns++;
4375 if (GTK_WIDGET_REALIZED (tree_view))
4379 for (list = tree_view->priv->columns; list; list = list->next)
4381 column = GTK_TREE_VIEW_COLUMN (list->data);
4382 if (column->visible)
4383 column->dirty = TRUE;
4385 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4388 return tree_view->priv->n_columns;
4392 * gtk_tree_view_insert_column_with_attributes:
4393 * @tree_view: A #GtkTreeView
4394 * @position: The position to insert the new column in.
4395 * @title: The title to set the header to.
4396 * @cell: The #GtkCellRenderer.
4397 * @Varargs: A NULL terminated list of attributes.
4399 * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
4400 * @position. If @position is -1, then the newly created column is inserted at
4401 * the end. The column is initialized with the attributes given.
4403 * Return value: The number of columns in @tree_view after insertion.
4406 gtk_tree_view_insert_column_with_attributes (GtkTreeView *tree_view,
4409 GtkCellRenderer *cell,
4412 GtkTreeViewColumn *column;
4417 g_return_val_if_fail (tree_view != NULL, -1);
4418 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4420 column = gtk_tree_view_column_new ();
4422 gtk_tree_view_column_set_title (column, title);
4423 gtk_tree_view_column_set_cell_renderer (column, cell);
4425 va_start (args, cell);
4427 attribute = va_arg (args, gchar *);
4429 while (attribute != NULL)
4431 column_id = va_arg (args, gint);
4432 gtk_tree_view_column_add_attribute (column, attribute, column_id);
4433 attribute = va_arg (args, gchar *);
4438 gtk_tree_view_insert_column (tree_view, column, position);
4439 g_object_unref (column);
4441 return tree_view->priv->n_columns;
4445 * gtk_tree_view_get_column:
4446 * @tree_view: A #GtkTreeView.
4447 * @n: The position of the column, counting from 0.
4449 * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
4451 * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
4455 gtk_tree_view_get_column (GtkTreeView *tree_view,
4458 g_return_val_if_fail (tree_view != NULL, NULL);
4459 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
4460 g_return_val_if_fail (tree_view->priv->model != NULL, NULL);
4462 if (n < 0 || n >= tree_view->priv->n_columns)
4465 if (tree_view->priv->columns == NULL)
4468 return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
4472 gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
4475 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4477 if (tree_view->priv->expander_column != col)
4479 tree_view->priv->expander_column = col;
4481 g_object_notify (G_OBJECT (tree_view), "expander_column");
4486 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
4488 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
4490 return tree_view->priv->expander_column;
4494 * gtk_tree_view_scroll_to_point:
4495 * @tree_view: a #GtkTreeView
4496 * @tree_x: X coordinate of new top-left pixel of visible area
4497 * @tree_y: Y coordinate of new top-left pixel of visible area
4499 * Scrolls the tree view such that the top-left corner of the visible
4500 * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
4501 * in tree window coordinates. The @tree_view must be realized before
4502 * this function is called. If it isn't, you probably want ot be
4503 * using gtk_tree_view_scroll_to_cell.
4506 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
4510 GtkAdjustment *hadj;
4511 GtkAdjustment *vadj;
4513 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4514 g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
4516 hadj = tree_view->priv->hadjustment;
4517 vadj = tree_view->priv->vadjustment;
4519 gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
4520 gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
4524 * gtk_tree_view_scroll_to_cell
4525 * @tree_view: A #GtkTreeView.
4526 * @path: The path of the row to move to.
4527 * @column: The #GtkTreeViewColumn to move horizontally to.
4528 * @row_align: The vertical alignment of the row specified by @path.
4529 * @col_align: The horizontal alignment of the column specified by @column.
4531 * Moves the alignments of @tree_view to the position specified by
4532 * @column and @path. If @column is NULL, then no horizontal
4533 * scrolling occurs. Likewise, if @path is NULL no vertical scrolling
4534 * occurs. @row_align determines where the row is placed, and
4535 * @col_align determines where @column is placed. Both are expected
4536 * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
4537 * right/bottom alignment, 0.5 means center.
4540 gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
4542 GtkTreeViewColumn *column,
4546 GdkRectangle cell_rect;
4547 GdkRectangle vis_rect;
4548 gint dest_x, dest_y;
4550 /* FIXME work on unmapped/unrealized trees? maybe implement when
4551 * we do incremental reflow for trees
4554 g_return_if_fail (tree_view != NULL);
4555 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4556 g_return_if_fail (row_align >= 0.0);
4557 g_return_if_fail (row_align <= 1.0);
4558 g_return_if_fail (col_align >= 0.0);
4559 g_return_if_fail (col_align <= 1.0);
4560 g_return_if_fail (path != NULL || column != NULL);
4562 row_align = CLAMP (row_align, 0.0, 1.0);
4563 col_align = CLAMP (col_align, 0.0, 1.0);
4565 if (! GTK_WIDGET_REALIZED (tree_view))
4568 tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
4570 tree_view->priv->scroll_to_column = column;
4571 tree_view->priv->scroll_to_row_align = row_align;
4572 tree_view->priv->scroll_to_col_align = col_align;
4577 gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
4578 gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
4580 dest_x = vis_rect.x;
4581 dest_y = vis_rect.y;
4585 dest_x = cell_rect.x +
4586 cell_rect.width * row_align -
4587 vis_rect.width * row_align;
4592 dest_y = cell_rect.y +
4593 cell_rect.height * col_align -
4594 vis_rect.height * col_align;
4597 gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
4601 * gtk_tree_view_get_path_at_pos:
4602 * @tree_view: A #GtkTreeView.
4603 * @window: The #GdkWindow to check against.
4604 * @x: The x position to be identified.
4605 * @y: The y position to be identified.
4606 * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
4607 * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
4608 * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
4609 * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
4611 * Finds the path at the point (@x, @y) relative to @window. If
4612 * @window is NULL, then the point is found relative to the widget
4613 * coordinates. This function is expected to be called after an
4614 * event, with event->window being passed in as @window. It is
4615 * primarily for things like popup menus. If @path is non-NULL, then
4616 * it will be filled with the #GtkTreePath at that point. This path
4617 * should be freed with #gtk_tree_path_free. If @column is non-NULL,
4618 * then it will be filled with the column at that point. @cell_x and
4619 * @cell_y return the coordinates relative to the cell background
4620 * (i.e. the background_area passed to gtk_cell_renderer_render()).
4622 * Return value: TRUE if a row exists at that coordinate.
4625 gtk_tree_view_get_path_at_pos (GtkTreeView *tree_view,
4630 GtkTreeViewColumn **column,
4638 g_return_val_if_fail (tree_view != NULL, FALSE);
4639 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
4640 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
4643 g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
4650 if (x > tree_view->priv->hadjustment->upper)
4656 if (column || cell_x)
4658 GtkTreeViewColumn *tmp_column;
4659 GtkTreeViewColumn *last_column = NULL;
4661 gint remaining_x = x;
4662 gboolean found = FALSE;
4664 for (list = tree_view->priv->columns; list; list = list->next)
4666 tmp_column = list->data;
4668 if (tmp_column->visible == FALSE)
4671 last_column = tmp_column;
4672 if (remaining_x <= tmp_column->width)
4677 *column = tmp_column;
4680 *cell_x = remaining_x;
4684 remaining_x -= tmp_column->width;
4690 *column = last_column;
4693 *cell_x = last_column->width + remaining_x;
4699 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
4700 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
4705 if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
4708 y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
4709 TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
4720 *path = _gtk_tree_view_find_path (tree_view, tree, node);
4727 gtk_tree_view_get_background_xrange (GtkTreeView *tree_view,
4729 GtkTreeViewColumn *column,
4733 GtkTreeViewColumn *tmp_column = NULL;
4744 for (list = tree_view->priv->columns; list; list = list->next)
4746 tmp_column = list->data;
4748 if (tmp_column == column)
4751 if (tmp_column->visible)
4752 total_width += tmp_column->width;
4755 if (tmp_column != column)
4757 g_warning (G_STRLOC": passed-in column isn't in the tree");
4766 if (column->visible)
4767 *x2 = total_width + column->width;
4769 *x2 = total_width; /* width of 0 */
4774 gtk_tree_view_get_cell_xrange (GtkTreeView *tree_view,
4776 GtkTreeViewColumn *column,
4780 GtkTreeViewColumn *tmp_column = NULL;
4793 for (list = tree_view->priv->columns; list; list = list->next)
4795 tmp_column = list->data;
4797 if (tmp_column == column)
4800 if (tmp_column->visible)
4801 total_width += tmp_column->width;
4806 if (tmp_column != column)
4808 g_warning (G_STRLOC": passed-in column isn't in the tree");
4812 /* Remember we're getting the cell range, i.e. the cell_area passed
4813 * to the cell renderer.
4816 if (i == tree_view->priv->expander_column)
4817 total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
4824 if (column->visible)
4825 *x2 = total_width + column->displayed_width;
4827 *x2 = total_width; /* width of 0 */
4832 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
4838 GtkTreeViewColumn *tmp_column = NULL;
4844 for (list = tree_view->priv->columns; list; list = list->next)
4846 tmp_column = list->data;
4848 if (i == tree_view->priv->expander_column)
4850 x_offset = total_width;
4854 if (tmp_column->visible)
4855 total_width += tmp_column->width;
4863 if (tmp_column && tmp_column->visible)
4865 /* +1 because x2 isn't included in the range. */
4867 *x2 = x_offset + tree_view->priv->tab_offset + 1;
4871 /* return an empty range, the expander column is hidden */
4879 * gtk_tree_view_get_cell_area:
4880 * @tree_view: a #GtkTreeView
4881 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
4882 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
4883 * @rect: rectangle to fill with cell rect
4885 * Fills the bounding rectangle in tree window coordinates for the
4886 * cell at the row specified by @path and the column specified by
4887 * @column. If @path is %NULL, the y and height fields of the
4888 * rectangle will be filled with 0. If @column is %NULL, the x and
4889 * width fields will be filled with 0. The sum of all cell rects does
4890 * not cover the entire tree; there are extra pixels in between rows,
4891 * for example. The returned rectangle is equivalent to the @cell_area
4892 * passed to gtk_cell_renderer_render().
4896 gtk_tree_view_get_cell_area (GtkTreeView *tree_view,
4898 GtkTreeViewColumn *column,
4901 GtkRBTree *tree = NULL;
4902 GtkRBNode *node = NULL;
4904 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4905 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
4906 g_return_if_fail (rect != NULL);
4915 /* Get vertical coords */
4917 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
4921 g_warning (G_STRLOC": no row corresponding to path");
4925 /* Remember that the rbtree stores node height including the vertical
4926 * separator, see comment at top of file.
4928 rect->y = CELL_FIRST_PIXEL (tree_view, tree, node);
4930 rect->height = CELL_HEIGHT (node);
4937 gtk_tree_view_get_cell_xrange (tree_view, tree, column, &rect->x, &x2);
4938 rect->width = x2 - rect->x;
4944 * gtk_tree_view_get_background_area:
4945 * @tree_view: a #GtkTreeView
4946 * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
4947 * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
4948 * @rect: rectangle to fill with cell background rect
4950 * Fills the bounding rectangle in tree window coordinates for the
4951 * cell at the row specified by @path and the column specified by
4952 * @column. If @path is %NULL, the y and height fields of the
4953 * rectangle will be filled with 0. If @column is %NULL, the x and
4954 * width fields will be filled with 0. The returned rectangle is
4955 * equivalent to the @background_area passed to
4956 * gtk_cell_renderer_render(). These background areas tile to cover
4957 * the entire tree window (except for the area used for header
4958 * buttons). Contrast with the cell_area, returned by
4959 * gtk_tree_view_get_cell_area(), which returns only the cell itself,
4960 * excluding surrounding borders and the tree expander area.
4964 gtk_tree_view_get_background_area (GtkTreeView *tree_view,
4966 GtkTreeViewColumn *column,
4969 GtkRBTree *tree = NULL;
4970 GtkRBNode *node = NULL;
4972 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4973 g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
4974 g_return_if_fail (rect != NULL);
4983 /* Get vertical coords */
4985 _gtk_tree_view_find_node (tree_view, path, &tree, &node);
4989 g_warning (G_STRLOC": no row corresponding to path");
4993 rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4995 rect->height = BACKGROUND_HEIGHT (node);
5002 gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
5003 rect->width = x2 - rect->x;
5008 gtk_tree_view_expand_all_helper (GtkRBTree *tree,
5012 GtkTreeView *tree_view = data;
5015 _gtk_rbtree_traverse (node->children,
5016 node->children->root,
5018 gtk_tree_view_expand_all_helper,
5020 else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
5026 node->children = _gtk_rbtree_new ();
5027 node->children->parent_tree = tree;
5028 node->children->parent_node = node;
5029 path = _gtk_tree_view_find_path (tree_view, tree, node);
5030 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5031 gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
5032 gtk_tree_view_build_tree (tree_view,
5035 gtk_tree_path_get_depth (path) + 1,
5037 GTK_WIDGET_REALIZED (tree_view));
5038 gtk_tree_path_free (path);
5043 * gtk_tree_view_expand_all:
5044 * @tree_view: A #GtkTreeView.
5046 * Recursively expands all nodes in the @tree_view.
5049 gtk_tree_view_expand_all (GtkTreeView *tree_view)
5051 g_return_if_fail (tree_view != NULL);
5052 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5053 g_return_if_fail (tree_view->priv->tree != NULL);
5055 _gtk_rbtree_traverse (tree_view->priv->tree,
5056 tree_view->priv->tree->root,
5058 gtk_tree_view_expand_all_helper,
5061 _gtk_tree_view_update_size (tree_view);
5065 gtk_tree_view_collapse_all_helper (GtkRBTree *tree,
5074 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
5076 node->children->root);
5077 gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
5080 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
5083 gtk_tree_path_get_depth (path));
5085 /* Ensure we don't have a dangling pointer to a dead node */
5086 ensure_unprelighted (GTK_TREE_VIEW (data));
5088 _gtk_rbtree_remove (node->children);
5089 gtk_tree_path_free (path);
5094 * gtk_tree_view_collapse_all:
5095 * @tree_view: A #GtkTreeView.
5097 * Recursively collapses all visible, expanded nodes in @tree_view.
5100 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
5102 g_return_if_fail (tree_view != NULL);
5103 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5104 g_return_if_fail (tree_view->priv->tree != NULL);
5106 _gtk_rbtree_traverse (tree_view->priv->tree,
5107 tree_view->priv->tree->root,
5109 gtk_tree_view_collapse_all_helper,
5112 if (GTK_WIDGET_MAPPED (tree_view))
5113 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5116 /* FIXME the bool return values for expand_row and collapse_row are
5117 * not analagous; they should be TRUE if the row had children and
5118 * was not already in the requested state.
5122 * gtk_tree_view_expand_row:
5123 * @tree_view: a #GtkTreeView
5124 * @path: path to a row
5125 * @open_all: whether to recursively expand, or just expand immediate children
5127 * Opens the row so its children are visible
5129 * Return value: %TRUE if the row existed and had children
5132 gtk_tree_view_expand_row (GtkTreeView *tree_view,
5141 g_return_val_if_fail (tree_view != NULL, FALSE);
5142 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5143 g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
5144 g_return_val_if_fail (path != NULL, FALSE);
5146 if (_gtk_tree_view_find_node (tree_view,
5155 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5156 if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
5159 node->children = _gtk_rbtree_new ();
5160 node->children->parent_tree = tree;
5161 node->children->parent_node = node;
5163 gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
5164 gtk_tree_view_build_tree (tree_view,
5167 gtk_tree_path_get_depth (path) + 1,
5169 GTK_WIDGET_REALIZED (tree_view));
5171 if (GTK_WIDGET_MAPPED (tree_view))
5172 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5178 * gtk_tree_view_collapse_row:
5179 * @tree_view: a #GtkTreeView
5180 * @path: path to a row in the @tree_view
5182 * Collapses a row (hides its child rows).
5184 * Return value: %TRUE if the row was expanded
5187 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
5194 g_return_val_if_fail (tree_view != NULL, FALSE);
5195 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5196 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
5197 g_return_val_if_fail (path != NULL, FALSE);
5199 if (_gtk_tree_view_find_node (tree_view,
5205 if (node->children == NULL)
5208 gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5209 gtk_tree_view_discover_dirty (tree_view,
5212 gtk_tree_path_get_depth (path));
5214 /* Ensure we don't have a dangling pointer to a dead node */
5215 ensure_unprelighted (tree_view);
5217 g_assert (tree_view->priv->prelight_node == NULL);
5219 _gtk_rbtree_remove (node->children);
5221 if (GTK_WIDGET_MAPPED (tree_view))
5222 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5228 * gtk_tree_view_get_visible_rect:
5229 * @tree_view: a #GtkTreeView
5230 * @visible_rect: rectangle to fill
5232 * Fills @visible_rect with the currently-visible region of the
5233 * buffer, in tree coordinates. Convert to widget coordinates with
5234 * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
5235 * 0,0 for row 0 of the tree, and cover the entire scrollable area of
5239 gtk_tree_view_get_visible_rect (GtkTreeView *tree_view,
5240 GdkRectangle *visible_rect)
5244 g_return_if_fail (tree_view != NULL);
5245 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5247 widget = GTK_WIDGET (tree_view);
5251 visible_rect->x = tree_view->priv->hadjustment->value;
5252 visible_rect->y = tree_view->priv->vadjustment->value;
5253 visible_rect->width = widget->allocation.width;
5254 visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5259 * gtk_tree_view_widget_to_tree_coords:
5260 * @tree_view: a #GtkTreeView
5261 * @wx: widget X coordinate
5262 * @wy: widget Y coordinate
5263 * @tx: return location for tree X coordinate
5264 * @ty: return location for tree Y coordinate
5266 * Converts widget coordinates to coordinates for the
5267 * tree window (the full scrollable area of the tree).
5271 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
5277 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5281 *tx = wx + tree_view->priv->hadjustment->value;
5286 *ty = wy + tree_view->priv->vadjustment->value;
5291 * gtk_tree_view_tree_to_widget_coords:
5292 * @tree_view: a #GtkTreeView
5293 * @tx: tree X coordinate
5294 * @ty: tree Y coordinate
5295 * @wx: return location for widget X coordinate
5296 * @wy: return location for widget Y coordinate
5298 * Converts tree coordinates (coordinates in full scrollable
5299 * area of the tree) to widget coordinates.
5303 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
5309 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5313 *wx = tx - tree_view->priv->hadjustment->value;
5318 *wy = ty - tree_view->priv->vadjustment->value;
5323 * gtk_tree_view_set_rules_hint
5324 * @tree_view: a #GtkTreeView
5325 * @setting: %TRUE if the tree requires reading across rows
5327 * This function tells GTK+ that the user interface for your
5328 * application requires users to read across tree rows and associate
5329 * cells with one another. By default, GTK+ will then render the tree
5330 * with alternating row colors. <emphasis>DO NOT</emphasis> use it
5331 * just because you prefer the appearance of the ruled tree; that's a
5332 * question for the theme. Some themes will draw tree rows in
5333 * alternating colors even when rules are turned off, and users who
5334 * prefer that appearance all the time can choose those themes. You
5335 * should call this function only as a <emphasis>semantic</emphasis>
5336 * hint to the theme engine that your tree makes alternating colors
5337 * useful from a functional standpoint (since it has lots of columns,
5342 gtk_tree_view_set_rules_hint (GtkTreeView *tree_view,
5345 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5347 setting = setting != FALSE;
5349 if (tree_view->priv->has_rules != setting)
5351 tree_view->priv->has_rules = setting;
5352 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5355 g_object_notify (G_OBJECT (tree_view), "rules_hint");
5359 * gtk_tree_view_get_rules_hint
5360 * @tree_view: a #GtkTreeView
5362 * Gets the setting set by gtk_tree_view_set_rules_hint().
5364 * Return value: %TRUE if rules are useful for the user of this tree
5367 gtk_tree_view_get_rules_hint (GtkTreeView *tree_view)
5369 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5371 return tree_view->priv->has_rules;
5377 set_source_row (GdkDragContext *context,
5378 GtkTreeModel *model,
5379 GtkTreePath *source_row)
5381 g_object_set_data_full (G_OBJECT (context),
5382 "gtk-tree-view-source-row",
5383 source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
5384 (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
5388 get_source_row (GdkDragContext *context)
5390 GtkTreeRowReference *ref =
5391 g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
5394 return gtk_tree_row_reference_get_path (ref);
5401 set_dest_row (GdkDragContext *context,
5402 GtkTreeModel *model,
5403 GtkTreePath *dest_row)
5405 g_object_set_data_full (G_OBJECT (context),
5406 "gtk-tree-view-dest-row",
5407 dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
5408 (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
5412 get_dest_row (GdkDragContext *context)
5414 GtkTreeRowReference *ref =
5415 g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
5418 return gtk_tree_row_reference_get_path (ref);
5423 /* Get/set whether drag_motion requested the drag data and
5424 * drag_data_received should thus not actually insert the data,
5425 * since the data doesn't result from a drop.
5428 set_status_pending (GdkDragContext *context,
5429 GdkDragAction suggested_action)
5431 g_object_set_data (G_OBJECT (context),
5432 "gtk-tree-view-status-pending",
5433 GINT_TO_POINTER (suggested_action));
5436 static GdkDragAction
5437 get_status_pending (GdkDragContext *context)
5439 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5440 "gtk-tree-view-status-pending"));
5443 typedef struct _TreeViewDragInfo TreeViewDragInfo;
5445 struct _TreeViewDragInfo
5447 GdkModifierType start_button_mask;
5448 GtkTargetList *source_target_list;
5449 GdkDragAction source_actions;
5450 GClosure *row_draggable_closure;
5452 GtkTargetList *dest_target_list;
5453 GClosure *location_droppable_closure;
5455 guint source_set : 1;
5459 static TreeViewDragInfo*
5460 get_info (GtkTreeView *tree_view)
5462 return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
5466 clear_source_info (TreeViewDragInfo *di)
5468 if (di->source_target_list)
5469 gtk_target_list_unref (di->source_target_list);
5471 if (di->row_draggable_closure)
5472 g_closure_unref (di->row_draggable_closure);
5474 di->source_target_list = NULL;
5475 di->row_draggable_closure = NULL;
5479 clear_dest_info (TreeViewDragInfo *di)
5481 if (di->location_droppable_closure)
5482 g_closure_unref (di->location_droppable_closure);
5484 if (di->dest_target_list)
5485 gtk_target_list_unref (di->dest_target_list);
5487 di->location_droppable_closure = NULL;
5488 di->dest_target_list = NULL;
5492 destroy_info (TreeViewDragInfo *di)
5494 clear_source_info (di);
5495 clear_dest_info (di);
5499 static TreeViewDragInfo*
5500 ensure_info (GtkTreeView *tree_view)
5502 TreeViewDragInfo *di;
5504 di = get_info (tree_view);
5508 di = g_new0 (TreeViewDragInfo, 1);
5510 g_object_set_data_full (G_OBJECT (tree_view),
5511 "gtk-tree-view-drag-info",
5513 (GDestroyNotify) destroy_info);
5520 remove_info (GtkTreeView *tree_view)
5522 g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
5525 #define SCROLL_EDGE_SIZE 15
5528 drag_scan_timeout (gpointer data)
5530 GtkTreeView *tree_view;
5532 GdkModifierType state;
5533 GtkTreePath *path = NULL;
5534 GtkTreeViewColumn *column = NULL;
5535 GdkRectangle visible_rect;
5537 tree_view = GTK_TREE_VIEW (data);
5539 gdk_window_get_pointer (tree_view->priv->bin_window,
5542 gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
5544 /* See if we are near the edge. */
5545 if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
5546 (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
5547 (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
5548 (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
5550 gtk_tree_view_get_path_at_pos (tree_view,
5551 tree_view->priv->bin_window,
5560 gtk_tree_view_scroll_to_cell (tree_view,
5565 gtk_tree_path_free (path);
5574 ensure_scroll_timeout (GtkTreeView *tree_view)
5576 if (tree_view->priv->scroll_timeout == 0)
5577 tree_view->priv->scroll_timeout = gtk_timeout_add (50, drag_scan_timeout, tree_view);
5581 remove_scroll_timeout (GtkTreeView *tree_view)
5583 if (tree_view->priv->scroll_timeout != 0)
5585 gtk_timeout_remove (tree_view->priv->scroll_timeout);
5586 tree_view->priv->scroll_timeout = 0;
5591 gtk_tree_view_set_rows_drag_source (GtkTreeView *tree_view,
5592 GdkModifierType start_button_mask,
5593 const GtkTargetEntry *targets,
5595 GdkDragAction actions,
5596 GtkTreeViewDraggableFunc row_draggable_func,
5599 TreeViewDragInfo *di;
5601 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5603 di = ensure_info (tree_view);
5604 clear_source_info (di);
5606 di->start_button_mask = start_button_mask;
5607 di->source_target_list = gtk_target_list_new (targets, n_targets);
5608 di->source_actions = actions;
5610 if (row_draggable_func)
5612 di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
5614 g_closure_ref (di->row_draggable_closure);
5615 g_closure_sink (di->row_draggable_closure);
5618 di->source_set = TRUE;
5622 gtk_tree_view_set_rows_drag_dest (GtkTreeView *tree_view,
5623 const GtkTargetEntry *targets,
5625 GdkDragAction actions,
5626 GtkTreeViewDroppableFunc location_droppable_func,
5629 TreeViewDragInfo *di;
5631 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5633 gtk_drag_dest_set (GTK_WIDGET (tree_view),
5639 di = ensure_info (tree_view);
5640 clear_dest_info (di);
5643 di->dest_target_list = gtk_target_list_new (targets, n_targets);
5645 if (location_droppable_func)
5647 di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
5649 g_closure_ref (di->location_droppable_closure);
5650 g_closure_sink (di->location_droppable_closure);
5653 di->dest_set = TRUE;
5657 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
5659 TreeViewDragInfo *di;
5661 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5663 di = get_info (tree_view);
5669 clear_source_info (di);
5670 di->source_set = FALSE;
5673 if (!di->dest_set && !di->source_set)
5674 remove_info (tree_view);
5679 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
5681 TreeViewDragInfo *di;
5683 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5685 di = get_info (tree_view);
5691 gtk_drag_dest_unset (GTK_WIDGET (tree_view));
5692 clear_dest_info (di);
5693 di->dest_set = FALSE;
5696 if (!di->dest_set && !di->source_set)
5697 remove_info (tree_view);
5702 gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
5704 GtkTreeViewDropPosition pos)
5706 GtkTreePath *current_dest;
5707 /* Note; this function is exported to allow a custom DND
5708 * implementation, so it can't touch TreeViewDragInfo
5711 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5713 current_dest = NULL;
5715 if (tree_view->priv->drag_dest_row)
5716 current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
5720 gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
5721 gtk_tree_path_free (current_dest);
5724 if (tree_view->priv->drag_dest_row)
5725 gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
5727 tree_view->priv->drag_dest_pos = pos;
5731 tree_view->priv->drag_dest_row =
5732 gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
5733 gtk_tree_view_queue_draw_path (tree_view, path, NULL);
5736 tree_view->priv->drag_dest_row = NULL;
5740 gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
5742 GtkTreeViewDropPosition *pos)
5744 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5748 if (tree_view->priv->drag_dest_row)
5749 *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
5755 *pos = tree_view->priv->drag_dest_pos;
5759 gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
5763 GtkTreeViewDropPosition *pos)
5766 gdouble offset_into_row;
5770 GtkTreeViewColumn *column = NULL;
5771 GtkTreePath *tmp_path = NULL;
5773 /* Note; this function is exported to allow a custom DND
5774 * implementation, so it can't touch TreeViewDragInfo
5777 g_return_val_if_fail (tree_view != NULL, FALSE);
5778 g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
5779 g_return_val_if_fail (drag_x >= 0, FALSE);
5780 g_return_val_if_fail (drag_y >= 0, FALSE);
5781 g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
5786 /* remember that drag_x and drag_y are in widget coords, convert to tree window */
5788 gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
5791 /* If in the top quarter of a row, we drop before that row; if
5792 * in the bottom quarter, drop after that row; if in the middle,
5793 * and the row has children, drop into the row.
5796 if (!gtk_tree_view_get_path_at_pos (tree_view,
5797 tree_view->priv->bin_window,
5805 gtk_tree_view_get_background_area (tree_view, tmp_path, column,
5808 offset_into_row = cell_y;
5813 gtk_tree_path_free (tmp_path);
5817 quarter = cell.height / 4.0;
5821 if (offset_into_row < quarter)
5823 *pos = GTK_TREE_VIEW_DROP_BEFORE;
5825 else if (offset_into_row < quarter * 2)
5827 *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
5829 else if (offset_into_row < quarter * 3)
5831 *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
5835 *pos = GTK_TREE_VIEW_DROP_AFTER;
5843 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
5844 GdkEventMotion *event)
5846 GdkDragContext *context;
5847 TreeViewDragInfo *di;
5848 GtkTreePath *path = NULL;
5850 gint cell_x, cell_y;
5851 GtkTreeModel *model;
5853 di = get_info (tree_view);
5858 if (tree_view->priv->pressed_button < 0)
5861 if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
5862 tree_view->priv->press_start_x,
5863 tree_view->priv->press_start_y,
5864 event->x, event->y))
5867 model = gtk_tree_view_get_model (tree_view);
5872 button = tree_view->priv->pressed_button;
5873 tree_view->priv->pressed_button = -1;
5875 gtk_tree_view_get_path_at_pos (tree_view,
5876 tree_view->priv->bin_window,
5877 tree_view->priv->press_start_x,
5878 tree_view->priv->press_start_y,
5887 /* FIXME if the path doesn't match the row_draggable predicate,
5888 * return FALSE and free path
5891 /* FIXME Check whether we're a start button, if not return FALSE and
5895 context = gtk_drag_begin (GTK_WIDGET (tree_view),
5896 di->source_target_list,
5901 gtk_drag_set_icon_default (context);
5906 row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
5909 gtk_drag_set_icon_pixmap (context,
5910 gdk_drawable_get_colormap (row_pix),
5913 /* the + 1 is for the black border in the icon */
5914 tree_view->priv->press_start_x + 1,
5917 gdk_pixmap_unref (row_pix);
5920 set_source_row (context, model, path);
5921 gtk_tree_path_free (path);
5926 /* Default signal implementations for the drag signals */
5929 gtk_tree_view_drag_begin (GtkWidget *widget,
5930 GdkDragContext *context)
5936 gtk_tree_view_drag_end (GtkWidget *widget,
5937 GdkDragContext *context)
5943 gtk_tree_view_drag_data_get (GtkWidget *widget,
5944 GdkDragContext *context,
5945 GtkSelectionData *selection_data,
5949 GtkTreeView *tree_view;
5950 GtkTreeModel *model;
5951 TreeViewDragInfo *di;
5952 GtkTreePath *source_row;
5954 tree_view = GTK_TREE_VIEW (widget);
5956 model = gtk_tree_view_get_model (tree_view);
5961 di = get_info (GTK_TREE_VIEW (widget));
5966 source_row = get_source_row (context);
5968 if (source_row == NULL)
5971 /* We can implement the GTK_TREE_MODEL_ROW target generically for
5972 * any model; for DragSource models there are some other targets
5976 if (GTK_IS_TREE_DRAG_SOURCE (model) &&
5977 gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
5982 /* If drag_data_get does nothing, try providing row data. */
5983 if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
5985 gtk_selection_data_set_tree_row (selection_data,
5991 gtk_tree_path_free (source_row);
5996 check_model_dnd (GtkTreeModel *model,
5997 GType required_iface,
5998 const gchar *signal)
6000 if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6002 g_warning ("You must override the default '%s' handler "
6003 "on GtkTreeView when using models that don't support "
6004 "the %s interface and enabling drag-and-drop. The simplest way to do this "
6005 "is to connect to '%s' and call "
6006 "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
6007 "the default handler from running. Look at the source code "
6008 "for the default handler in gtktreeview.c to get an idea what "
6009 "your handler should do. (gtktreeview.c is in the GTK source "
6010 "code.) If you're using GTK from a language other than C, "
6011 "there may be a more natural way to override default handlers, e.g. via derivation.",
6012 signal, g_type_name (required_iface), signal);
6020 gtk_tree_view_drag_data_delete (GtkWidget *widget,
6021 GdkDragContext *context)
6023 TreeViewDragInfo *di;
6024 GtkTreeModel *model;
6025 GtkTreeView *tree_view;
6026 GtkTreePath *source_row;
6028 tree_view = GTK_TREE_VIEW (widget);
6029 model = gtk_tree_view_get_model (tree_view);
6031 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
6034 di = get_info (tree_view);
6039 source_row = get_source_row (context);
6041 if (source_row == NULL)
6044 gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6047 gtk_tree_path_free (source_row);
6049 set_source_row (context, NULL, NULL);
6053 remove_open_timeout (GtkTreeView *tree_view)
6055 if (tree_view->priv->open_dest_timeout != 0)
6057 gtk_timeout_remove (tree_view->priv->open_dest_timeout);
6058 tree_view->priv->open_dest_timeout = 0;
6063 gtk_tree_view_drag_leave (GtkWidget *widget,
6064 GdkDragContext *context,
6067 TreeViewDragInfo *di;
6069 di = get_info (GTK_TREE_VIEW (widget));
6071 /* unset any highlight row */
6072 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6074 GTK_TREE_VIEW_DROP_BEFORE);
6076 remove_scroll_timeout (GTK_TREE_VIEW (widget));
6077 remove_open_timeout (GTK_TREE_VIEW (widget));
6081 open_row_timeout (gpointer data)
6083 GtkTreeView *tree_view = data;
6084 GtkTreePath *dest_path = NULL;
6085 GtkTreeViewDropPosition pos;
6087 gtk_tree_view_get_drag_dest_row (tree_view,
6092 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6093 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6095 gtk_tree_view_expand_row (tree_view,
6098 tree_view->priv->open_dest_timeout = 0;
6100 gtk_tree_path_free (dest_path);
6107 gtk_tree_path_free (dest_path);
6112 /* Returns TRUE if event should not be propagated to parent widgets */
6114 set_destination_row (GtkTreeView *tree_view,
6115 GdkDragContext *context,
6118 GdkDragAction *suggested_action,
6121 GtkTreePath *path = NULL;
6122 GtkTreeViewDropPosition pos;
6123 GtkTreeViewDropPosition old_pos;
6124 TreeViewDragInfo *di;
6126 GtkTreePath *old_dest_path = NULL;
6128 *suggested_action = 0;
6131 widget = GTK_WIDGET (tree_view);
6133 di = get_info (tree_view);
6137 /* someone unset us as a drag dest, note that if
6138 * we return FALSE drag_leave isn't called
6141 gtk_tree_view_set_drag_dest_row (tree_view,
6143 GTK_TREE_VIEW_DROP_BEFORE);
6145 remove_scroll_timeout (GTK_TREE_VIEW (widget));
6146 remove_open_timeout (GTK_TREE_VIEW (widget));
6148 return FALSE; /* no longer a drop site */
6151 *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
6152 if (*target == GDK_NONE)
6157 if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6162 /* can't drop here */
6163 remove_open_timeout (tree_view);
6165 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6167 GTK_TREE_VIEW_DROP_BEFORE);
6169 /* don't propagate to parent though */
6175 /* If we left the current row's "open" zone, unset the timeout for
6178 gtk_tree_view_get_drag_dest_row (tree_view,
6182 if (old_dest_path &&
6183 (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6184 !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6185 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6186 remove_open_timeout (tree_view);
6189 gtk_tree_path_free (old_dest_path);
6191 if (TRUE /* FIXME if the location droppable predicate */)
6193 GtkWidget *source_widget;
6195 *suggested_action = context->suggested_action;
6197 source_widget = gtk_drag_get_source_widget (context);
6199 if (source_widget == widget)
6201 /* Default to MOVE, unless the user has
6202 * pressed ctrl or alt to affect available actions
6204 if ((context->actions & GDK_ACTION_MOVE) != 0)
6205 *suggested_action = GDK_ACTION_MOVE;
6208 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6213 /* can't drop here */
6214 remove_open_timeout (tree_view);
6216 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6218 GTK_TREE_VIEW_DROP_BEFORE);
6225 gtk_tree_view_drag_motion (GtkWidget *widget,
6226 GdkDragContext *context,
6231 GtkTreePath *path = NULL;
6232 GtkTreeViewDropPosition pos;
6233 GtkTreeView *tree_view;
6234 GdkDragAction suggested_action = 0;
6237 tree_view = GTK_TREE_VIEW (widget);
6239 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
6242 ensure_scroll_timeout (tree_view);
6244 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6248 /* Can't drop here. */
6249 gdk_drag_status (context, 0, time);
6253 if (tree_view->priv->open_dest_timeout == 0 &&
6254 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6255 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6257 tree_view->priv->open_dest_timeout =
6258 gtk_timeout_add (500, open_row_timeout, tree_view);
6261 if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
6263 /* Request data so we can use the source row when
6264 * determining whether to accept the drop
6266 set_status_pending (context, suggested_action);
6267 gtk_drag_get_data (widget, context, target, time);
6271 set_status_pending (context, 0);
6272 gdk_drag_status (context, suggested_action, time);
6277 gtk_tree_path_free (path);
6283 get_logical_dest_row (GtkTreeView *tree_view)
6286 /* adjust path to point to the row the drop goes in front of */
6287 GtkTreePath *path = NULL;
6288 GtkTreeViewDropPosition pos;
6290 gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6295 if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6297 else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6298 pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6300 /* get first child, drop before it */
6301 gtk_tree_path_append_index (path, 0);
6305 g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6306 gtk_tree_path_next (path);
6313 gtk_tree_view_drag_drop (GtkWidget *widget,
6314 GdkDragContext *context,
6319 GtkTreeView *tree_view;
6321 GdkDragAction suggested_action = 0;
6322 GdkAtom target = GDK_NONE;
6323 TreeViewDragInfo *di;
6324 GtkTreeModel *model;
6326 tree_view = GTK_TREE_VIEW (widget);
6328 model = gtk_tree_view_get_model (tree_view);
6330 remove_scroll_timeout (GTK_TREE_VIEW (widget));
6331 remove_open_timeout (GTK_TREE_VIEW (widget));
6333 di = get_info (tree_view);
6338 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
6341 if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
6344 path = get_logical_dest_row (tree_view);
6346 if (target != GDK_NONE && path != NULL)
6348 /* in case a motion had requested drag data, change things so we
6349 * treat drag data receives as a drop.
6351 set_status_pending (context, 0);
6353 set_dest_row (context, model, path);
6357 gtk_tree_path_free (path);
6359 /* Unset this thing */
6360 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6362 GTK_TREE_VIEW_DROP_BEFORE);
6364 if (target != GDK_NONE)
6366 gtk_drag_get_data (widget, context, target, time);
6374 gtk_tree_view_drag_data_received (GtkWidget *widget,
6375 GdkDragContext *context,
6378 GtkSelectionData *selection_data,
6383 TreeViewDragInfo *di;
6384 gboolean accepted = FALSE;
6385 GtkTreeModel *model;
6386 GtkTreeView *tree_view;
6387 GtkTreePath *dest_row;
6388 GdkDragAction suggested_action;
6390 tree_view = GTK_TREE_VIEW (widget);
6392 model = gtk_tree_view_get_model (tree_view);
6394 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
6397 di = get_info (tree_view);
6402 suggested_action = get_status_pending (context);
6404 if (suggested_action)
6406 /* We are getting this data due to a request in drag_motion,
6407 * rather than due to a request in drag_drop, so we are just
6408 * supposed to call drag_status, not actually paste in the
6411 path = get_logical_dest_row (tree_view);
6414 suggested_action = 0;
6416 if (suggested_action)
6418 GtkTreeModel *src_model = NULL;
6419 GtkTreePath *src_path = NULL;
6421 if (!gtk_selection_data_get_tree_row (selection_data,
6424 suggested_action = 0;
6426 if (suggested_action)
6428 if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6432 suggested_action = 0;
6434 gtk_tree_path_free (src_path);
6438 gdk_drag_status (context, suggested_action, time);
6441 gtk_tree_path_free (path);
6443 /* If you can't drop, remove user drop indicator until the next motion */
6444 if (suggested_action == 0)
6445 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6447 GTK_TREE_VIEW_DROP_BEFORE);
6452 dest_row = get_dest_row (context);
6454 if (dest_row == NULL)
6457 if (selection_data->length >= 0)
6459 if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6465 gtk_drag_finish (context,
6467 (context->action == GDK_ACTION_MOVE),
6470 gtk_tree_path_free (dest_row);
6473 set_dest_row (context, NULL, NULL);