]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
New function for language bindings.
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20
21 #include "gtktreeview.h"
22 #include "gtkrbtree.h"
23 #include "gtktreednd.h"
24 #include "gtktreeprivate.h"
25 #include "gtkcellrenderer.h"
26 #include "gtksignal.h"
27 #include "gtkmain.h"
28 #include "gtkbutton.h"
29 #include "gtkalignment.h"
30 #include "gtklabel.h"
31 #include "gtkhbox.h"
32 #include "gtkarrow.h"
33 #include "gtkintl.h"
34 #include "gtkbindings.h"
35
36 #include <gdk/gdkkeysyms.h>
37
38 #if defined (GDK_WINDOWING_X11)
39 #include "x11/gdkx.h"
40 #elif defined (GDK_WINDOWING_WIN32)
41 #include "win32/gdkwin32.h"
42 #elif defined(GDK_WINDOWING_FB)
43 #include "linux-fb/gdkfb.h"
44 #elif defined (GDK_WINDOWING_NANOX)
45 #include "nanox/gdkprivate-nanox.h"
46 #endif
47
48
49 #define SCROLL_EDGE_SIZE 15
50
51
52 /* The "background" areas of all rows/cells add up to cover the entire tree.
53  * The background includes all inter-row and inter-cell spacing.
54  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
55  * i.e. just the cells, no spacing.
56  */
57 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (_gtk_rbtree_node_find_offset ((tree), (node)) + TREE_VIEW_HEADER_HEIGHT ((tree_view)))
58 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
59
60 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
61 #define CELL_HEIGHT(node, separator) (BACKGROUND_HEIGHT (node) - separator);
62
63 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view))
64 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view))
65
66
67 typedef struct _GtkTreeViewChild GtkTreeViewChild;
68 struct _GtkTreeViewChild
69 {
70   GtkWidget *widget;
71   gint x;
72   gint y;
73 };
74
75
76 typedef struct _TreeViewDragInfo TreeViewDragInfo;
77 struct _TreeViewDragInfo
78 {
79   GdkModifierType start_button_mask;
80   GtkTargetList *source_target_list;
81   GdkDragAction source_actions;
82   GClosure *row_draggable_closure;
83
84   GtkTargetList *dest_target_list;
85   GClosure *location_droppable_closure;
86
87   guint source_set : 1;
88   guint dest_set : 1;
89 };
90
91
92 /* Signals */
93 enum
94 {
95   ROW_ACTIVATED,
96   TEST_EXPAND_ROW,
97   TEST_COLLAPSE_ROW,
98   ROW_EXPANDED,
99   ROW_COLLAPSED,
100   COLUMNS_CHANGED,
101   BEGIN_EXTENDED_SELECTION,
102   END_EXTENDED_SELECTION,
103   BEGIN_FREE_MOTION,
104   END_FREE_MOTION,
105   MOVE_CURSOR,
106   SELECT_CURSOR_ROW,
107   TOGGLE_CURSOR_ROW,
108   EXPAND_COLLAPSE_CURSOR_ROW,
109   SELECT_CURSOR_PARENT,
110   LAST_SIGNAL
111 };
112
113 /* Properties */
114 enum {
115   PROP_0,
116   PROP_MODEL,
117   PROP_HADJUSTMENT,
118   PROP_VADJUSTMENT,
119   PROP_HEADERS_VISIBLE,
120   PROP_HEADERS_CLICKABLE,
121   PROP_EXPANDER_COLUMN,
122   PROP_REORDERABLE,
123   PROP_RULES_HINT
124 };
125
126 static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
127 static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);
128
129 /* object signals */
130 static void     gtk_tree_view_finalize             (GObject          *object);
131 static void     gtk_tree_view_set_property         (GObject         *object,
132                                                     guint            prop_id,
133                                                     const GValue    *value,
134                                                     GParamSpec      *pspec);
135 static void     gtk_tree_view_get_property         (GObject         *object,
136                                                     guint            prop_id,
137                                                     GValue          *value,
138                                                     GParamSpec      *pspec);
139
140 /* gtkobject signals */
141 static void     gtk_tree_view_destroy              (GtkObject        *object);
142
143 /* gtkwidget signals */
144 static void     gtk_tree_view_setup_model          (GtkTreeView      *tree_view);
145 static void     gtk_tree_view_realize              (GtkWidget        *widget);
146 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
147 static void     gtk_tree_view_map                  (GtkWidget        *widget);
148 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
149                                                     GtkRequisition   *requisition);
150 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
151                                                     GtkAllocation    *allocation);
152 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
153                                                     GdkEventExpose   *event);
154 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
155                                                     GdkEventKey      *event);
156 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
157                                                     GdkEventMotion   *event);
158 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
159                                                     GdkEventCrossing *event);
160 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
161                                                     GdkEventCrossing *event);
162 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
163                                                     GdkEventButton   *event);
164 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
165                                                     GdkEventButton   *event);
166 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
167                                                     GtkWidget        *child);
168 static void     gtk_tree_view_draw_focus           (GtkWidget        *widget);
169 static gint     gtk_tree_view_focus_in             (GtkWidget        *widget,
170                                                     GdkEventFocus    *event);
171 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
172                                                     GdkEventFocus    *event);
173 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
174                                                     GtkDirectionType  direction);
175
176 /* container signals */
177 static void     gtk_tree_view_remove               (GtkContainer     *container,
178                                                     GtkWidget        *widget);
179 static void     gtk_tree_view_forall               (GtkContainer     *container,
180                                                     gboolean          include_internals,
181                                                     GtkCallback       callback,
182                                                     gpointer          callback_data);
183
184 /* Source side drag signals */
185 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
186                                             GdkDragContext   *context);
187 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
188                                             GdkDragContext   *context);
189 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
190                                             GdkDragContext   *context,
191                                             GtkSelectionData *selection_data,
192                                             guint             info,
193                                             guint             time);
194 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
195                                             GdkDragContext   *context);
196
197 /* Target side drag signals */
198 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
199                                                   GdkDragContext   *context,
200                                                   guint             time);
201 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
202                                                   GdkDragContext   *context,
203                                                   gint              x,
204                                                   gint              y,
205                                                   guint             time);
206 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
207                                                   GdkDragContext   *context,
208                                                   gint              x,
209                                                   gint              y,
210                                                   guint             time);
211 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
212                                                   GdkDragContext   *context,
213                                                   gint              x,
214                                                   gint              y,
215                                                   GtkSelectionData *selection_data,
216                                                   guint             info,
217                                                   guint             time);
218
219 /* tree_model signals */
220 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
221                                                            GtkAdjustment   *hadj,
222                                                            GtkAdjustment   *vadj);
223 static void gtk_tree_view_real_begin_extended_selection   (GtkTreeView     *tree_view);
224 static void gtk_tree_view_real_end_extended_selection     (GtkTreeView     *tree_view);
225 static void gtk_tree_view_real_begin_free_motion          (GtkTreeView     *tree_view);
226 static void gtk_tree_view_real_end_free_motion            (GtkTreeView     *tree_view);
227 static void gtk_tree_view_real_move_cursor                (GtkTreeView     *tree_view,
228                                                            GtkMovementStep  step,
229                                                            gint             count);
230 static void gtk_tree_view_real_select_cursor_row          (GtkTreeView     *tree_view);
231 static void gtk_tree_view_real_toggle_cursor_row          (GtkTreeView     *tree_view);
232 static void gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
233                                                            gboolean         logical,
234                                                            gboolean         expand,
235                                                            gboolean         open_all);
236 static void gtk_tree_view_real_select_cursor_parent       (GtkTreeView     *tree_view);
237 static void gtk_tree_view_range_changed                   (GtkTreeModel    *model,
238                                                            GtkTreePath     *path,
239                                                            GtkTreeIter     *iter,
240                                                            GtkTreePath     *end_path,
241                                                            GtkTreeIter     *end_iter,
242                                                            gpointer         data);
243 static void gtk_tree_view_inserted                        (GtkTreeModel    *model,
244                                                            GtkTreePath     *path,
245                                                            GtkTreeIter     *iter,
246                                                            gpointer         data);
247 static void gtk_tree_view_has_child_toggled               (GtkTreeModel    *model,
248                                                            GtkTreePath     *path,
249                                                            GtkTreeIter     *iter,
250                                                            gpointer         data);
251 static void gtk_tree_view_deleted                         (GtkTreeModel    *model,
252                                                            GtkTreePath     *path,
253                                                            gpointer         data);
254 static void gtk_tree_view_reordered                       (GtkTreeModel    *model,
255                                                            GtkTreePath     *parent,
256                                                            GtkTreeIter     *iter,
257                                                            gint            *new_order,
258                                                            gpointer         data);
259
260
261
262 /* Internal functions */
263 static gboolean gtk_tree_view_is_expander_column   (GtkTreeView      *tree_view,
264                                                     GtkTreeViewColumn*column);
265 static void     gtk_tree_view_add_move_binding     (GtkBindingSet    *binding_set,
266                                                     guint             keyval,
267                                                     guint             modmask,
268                                                     GtkMovementStep   step,
269                                                     gint              count);
270 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView      *tree_view,
271                                                               GtkRBTree        *tree);
272 static void     gtk_tree_view_queue_draw_node      (GtkTreeView      *tree_view,
273                                                     GtkRBTree        *tree,
274                                                     GtkRBNode        *node,
275                                                     GdkRectangle     *clip_rect);
276 static void     gtk_tree_view_queue_draw_path      (GtkTreeView      *tree_view,
277                                                     GtkTreePath      *path,
278                                                     GdkRectangle     *clip_rect);
279 static void     gtk_tree_view_draw_arrow           (GtkTreeView      *tree_view,
280                                                     GtkRBTree        *tree,
281                                                     GtkRBNode        *node,
282                                                     gint              x,
283                                                     gint              y);
284 static void     gtk_tree_view_get_arrow_xrange     (GtkTreeView      *tree_view,
285                                                     gint              *x1,
286                                                     gint              *x2);
287 static gint     gtk_tree_view_new_column_width     (GtkTreeView      *tree_view,
288                                                     gint              i,
289                                                     gint             *x);
290 static void     gtk_tree_view_ensure_scroll_timeout(GtkTreeView      *tree_view,
291                                                     GFunc             func);
292 static void     gtk_tree_view_adjustment_changed   (GtkAdjustment    *adjustment,
293                                                     GtkTreeView      *tree_view);
294 static gint     gtk_tree_view_insert_iter_height   (GtkTreeView      *tree_view,
295                                                     GtkRBTree        *tree,
296                                                     GtkTreeIter      *iter,
297                                                     gint              depth);
298 static void     gtk_tree_view_build_tree           (GtkTreeView      *tree_view,
299                                                     GtkRBTree        *tree,
300                                                     GtkTreeIter      *iter,
301                                                     gint              depth,
302                                                     gboolean          recurse,
303                                                     gboolean          calc_bounds);
304 static void     gtk_tree_view_calc_size            (GtkTreeView      *priv,
305                                                     GtkRBTree        *tree,
306                                                     GtkTreeIter      *iter,
307                                                     gint              depth);
308 static gboolean gtk_tree_view_discover_dirty_iter  (GtkTreeView      *tree_view,
309                                                     GtkTreeIter      *iter,
310                                                     gint              depth,
311                                                     gint             *height);
312 static void     gtk_tree_view_discover_dirty       (GtkTreeView      *tree_view,
313                                                     GtkRBTree        *tree,
314                                                     GtkTreeIter      *iter,
315                                                     gint              depth);
316 static void     gtk_tree_view_check_dirty          (GtkTreeView      *tree_view);
317 static void     gtk_tree_view_clamp_node_visible   (GtkTreeView      *tree_view,
318                                                     GtkRBTree        *tree,
319                                                     GtkRBNode        *node);
320 static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
321                                                         GdkEventMotion   *event);
322 static void     _gtk_tree_view_update_col_width    (GtkTreeView      *tree_view);
323
324
325 static void gtk_tree_view_focus_to_cursor          (GtkTreeView *tree_view);
326 static void gtk_tree_view_move_cursor_up_down      (GtkTreeView *tree_view,
327                                                     gint         count);
328 static void gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
329                                                     gint         count);
330 static void gtk_tree_view_move_cursor_left_right   (GtkTreeView *tree_view,
331                                                     gint         count);
332 static void gtk_tree_view_move_cursor_start_end    (GtkTreeView *tree_view,
333                                                     gint         count);
334 static gboolean gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
335                                                  GtkTreePath *path,
336                                                  GtkRBTree   *tree,
337                                                  GtkRBNode   *node);
338 static gboolean gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
339                                                GtkTreePath *path,
340                                                GtkRBTree   *tree,
341                                                GtkRBNode   *node,
342                                                gboolean     open_all);
343 static void gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
344                                            GtkTreePath     *path,
345                                            gboolean         clear_and_select);
346
347
348 static GtkContainerClass *parent_class = NULL;
349 static guint tree_view_signals[LAST_SIGNAL] = { 0 };
350
351 \f
352
353 /* GType Methods
354  */
355
356 GtkType
357 gtk_tree_view_get_type (void)
358 {
359   static GtkType tree_view_type = 0;
360
361   if (!tree_view_type)
362     {
363       static const GTypeInfo tree_view_info =
364       {
365         sizeof (GtkTreeViewClass),
366         NULL,           /* base_init */
367         NULL,           /* base_finalize */
368         (GClassInitFunc) gtk_tree_view_class_init,
369         NULL,           /* class_finalize */
370         NULL,           /* class_data */
371         sizeof (GtkTreeView),
372         0,              /* n_preallocs */
373         (GInstanceInitFunc) gtk_tree_view_init
374       };
375
376       tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
377     }
378
379   return tree_view_type;
380 }
381
382 static void
383 gtk_tree_view_class_init (GtkTreeViewClass *class)
384 {
385   GObjectClass *o_class;
386   GtkObjectClass *object_class;
387   GtkWidgetClass *widget_class;
388   GtkContainerClass *container_class;
389   GtkBindingSet *binding_set;
390
391   parent_class = g_type_class_peek_parent (class);
392   binding_set = gtk_binding_set_by_class (class);
393
394   o_class = (GObjectClass *) class;
395   object_class = (GtkObjectClass *) class;
396   widget_class = (GtkWidgetClass *) class;
397   container_class = (GtkContainerClass *) class;
398
399   /* GObject signals */
400   o_class->set_property = gtk_tree_view_set_property;
401   o_class->get_property = gtk_tree_view_get_property;
402   o_class->finalize = gtk_tree_view_finalize;
403
404   /* GtkObject signals */
405   object_class->destroy = gtk_tree_view_destroy;
406
407   /* GtkWidget signals */
408   widget_class->map = gtk_tree_view_map;
409   widget_class->realize = gtk_tree_view_realize;
410   widget_class->unrealize = gtk_tree_view_unrealize;
411   widget_class->size_request = gtk_tree_view_size_request;
412   widget_class->size_allocate = gtk_tree_view_size_allocate;
413   widget_class->button_press_event = gtk_tree_view_button_press;
414   widget_class->button_release_event = gtk_tree_view_button_release;
415   widget_class->motion_notify_event = gtk_tree_view_motion;
416   widget_class->expose_event = gtk_tree_view_expose;
417   widget_class->key_press_event = gtk_tree_view_key_press;
418   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
419   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
420   widget_class->focus_in_event = gtk_tree_view_focus_in;
421   widget_class->focus_out_event = gtk_tree_view_focus_out;
422   widget_class->drag_begin = gtk_tree_view_drag_begin;
423   widget_class->drag_end = gtk_tree_view_drag_end;
424   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
425   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
426   widget_class->drag_leave = gtk_tree_view_drag_leave;
427   widget_class->drag_motion = gtk_tree_view_drag_motion;
428   widget_class->drag_drop = gtk_tree_view_drag_drop;
429   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
430   widget_class->focus = gtk_tree_view_focus;
431
432   /* GtkContainer signals */
433   container_class->remove = gtk_tree_view_remove;
434   container_class->forall = gtk_tree_view_forall;
435   container_class->set_focus_child = gtk_tree_view_set_focus_child;
436
437   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
438   class->begin_extended_selection = gtk_tree_view_real_begin_extended_selection;
439   class->end_extended_selection = gtk_tree_view_real_end_extended_selection;
440   class->begin_free_motion = gtk_tree_view_real_begin_free_motion;
441   class->end_free_motion = gtk_tree_view_real_end_free_motion;
442   class->move_cursor = gtk_tree_view_real_move_cursor;
443   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
444   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
445   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
446   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
447
448   /* Properties */
449
450   g_object_class_install_property (o_class,
451                                    PROP_MODEL,
452                                    g_param_spec_object ("model",
453                                                         _("TreeView Model"),
454                                                         _("The model for the tree view"),
455                                                         GTK_TYPE_TREE_MODEL,
456                                                         G_PARAM_READWRITE));
457
458   g_object_class_install_property (o_class,
459                                    PROP_HADJUSTMENT,
460                                    g_param_spec_object ("hadjustment",
461                                                         _("Horizontal Adjustment"),
462                                                         _("Horizontal Adjustment for the widget"),
463                                                         GTK_TYPE_ADJUSTMENT,
464                                                         G_PARAM_READWRITE));
465
466   g_object_class_install_property (o_class,
467                                    PROP_VADJUSTMENT,
468                                    g_param_spec_object ("vadjustment",
469                                                         _("Vertical Adjustment"),
470                                                         _("Vertical Adjustment for the widget"),
471                                                         GTK_TYPE_ADJUSTMENT,
472                                                         G_PARAM_READWRITE));
473
474   g_object_class_install_property (o_class,
475                                    PROP_HEADERS_VISIBLE,
476                                    g_param_spec_boolean ("headers_visible",
477                                                          _("Visible"),
478                                                          _("Show the column header buttons"),
479                                                          FALSE,
480                                                          G_PARAM_READWRITE));
481
482   g_object_class_install_property (o_class,
483                                    PROP_HEADERS_CLICKABLE,
484                                    g_param_spec_boolean ("headers_clickable",
485                                                          _("Headers Clickable"),
486                                                          _("Column headers respond to click events"),
487                                                          FALSE,
488                                                          G_PARAM_WRITABLE));
489
490   g_object_class_install_property (o_class,
491                                    PROP_EXPANDER_COLUMN,
492                                    g_param_spec_object ("expander_column",
493                                                         _("Expander Column"),
494                                                         _("Set the column for the expander column"),
495                                                         GTK_TYPE_TREE_VIEW_COLUMN,
496                                                         G_PARAM_READWRITE));
497
498   g_object_class_install_property (o_class,
499                                    PROP_REORDERABLE,
500                                    g_param_spec_boolean ("reorderable",
501                                                          _("Reorderable"),
502                                                          _("View is reorderable"),
503                                                          FALSE,
504                                                          G_PARAM_READWRITE));
505
506   g_object_class_install_property (o_class,
507                                    PROP_RULES_HINT,
508                                    g_param_spec_boolean ("rules_hint",
509                                                          _("Rules Hint"),
510                                                          _("Set a hint to the theme engine to draw rows in alternating colors"),
511                                                          FALSE,
512                                                          G_PARAM_READWRITE));
513
514   /* Style properties */
515   /* the width of the column resize windows */
516 #define _TREE_VIEW_EXPANDER_WIDTH 14
517 #define _TREE_VIEW_EXPANDER_HEIGHT 14
518 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
519 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 0
520
521   gtk_widget_class_install_style_property (widget_class,
522                                            g_param_spec_int ("expander_width",
523                                                              _("Expander Width"),
524                                                              _("Width of the expander arrow"),
525                                                              0,
526                                                              G_MAXINT,
527                                                              _TREE_VIEW_EXPANDER_WIDTH,
528                                                              G_PARAM_READABLE));
529
530   gtk_widget_class_install_style_property (widget_class,
531                                            g_param_spec_int ("expander_height",
532                                                              _("Expander Height"),
533                                                              _("Height of the expander arrow"),
534                                                              4,
535                                                              G_MAXINT,
536                                                              _TREE_VIEW_EXPANDER_HEIGHT,
537                                                              G_PARAM_READABLE));
538
539     gtk_widget_class_install_style_property (widget_class,
540                                            g_param_spec_int ("vertical_separator",
541                                                              _("Vertical Separator Width"),
542                                                              _("Vertical space between cells"),
543                                                              0,
544                                                              G_MAXINT,
545                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
546                                                              G_PARAM_READABLE));
547
548     gtk_widget_class_install_style_property (widget_class,
549                                            g_param_spec_int ("horizontal_separator",
550                                                              _("Horizontal Separator Width"),
551                                                              _("Horizontal space between cells"),
552                                                              0,
553                                                              G_MAXINT,
554                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
555                                                              G_PARAM_READABLE));
556
557   /* Signals */
558   widget_class->set_scroll_adjustments_signal =
559     gtk_signal_new ("set_scroll_adjustments",
560                     GTK_RUN_LAST,
561                     GTK_CLASS_TYPE (object_class),
562                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
563                     gtk_marshal_VOID__OBJECT_OBJECT,
564                     GTK_TYPE_NONE, 2,
565                     GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
566
567   tree_view_signals[ROW_ACTIVATED] =
568     gtk_signal_new ("row_activated",
569                     GTK_RUN_LAST | GTK_RUN_ACTION,
570                     GTK_CLASS_TYPE (object_class),
571                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
572                     gtk_marshal_VOID__BOXED_OBJECT,
573                     GTK_TYPE_NONE, 2,
574                     GTK_TYPE_TREE_PATH,
575                     GTK_TYPE_TREE_VIEW_COLUMN);
576
577   tree_view_signals[TEST_EXPAND_ROW] =
578     g_signal_new ("test_expand_row",
579                   G_TYPE_FROM_CLASS (object_class),
580                   G_SIGNAL_RUN_LAST,
581                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
582                   _gtk_boolean_handled_accumulator, NULL,
583                   gtk_marshal_BOOLEAN__BOXED_BOXED,
584                   G_TYPE_BOOLEAN, 2,
585                   GTK_TYPE_TREE_ITER,
586                   GTK_TYPE_TREE_PATH);
587
588   tree_view_signals[TEST_COLLAPSE_ROW] =
589     g_signal_new ("test_collapse_row",
590                   G_TYPE_FROM_CLASS (object_class),
591                   G_SIGNAL_RUN_LAST,
592                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
593                   _gtk_boolean_handled_accumulator, NULL,
594                   gtk_marshal_BOOLEAN__BOXED_BOXED,
595                   G_TYPE_BOOLEAN, 2,
596                   GTK_TYPE_TREE_ITER,
597                   GTK_TYPE_TREE_PATH);
598
599   tree_view_signals[ROW_EXPANDED] =
600     g_signal_new ("row_expanded",
601                   G_TYPE_FROM_CLASS (object_class),
602                   G_SIGNAL_RUN_LAST,
603                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
604                   NULL, NULL,
605                   gtk_marshal_VOID__BOXED_BOXED,
606                   GTK_TYPE_NONE, 2,
607                   GTK_TYPE_TREE_ITER,
608                   GTK_TYPE_TREE_PATH);
609
610   tree_view_signals[ROW_COLLAPSED] =
611     g_signal_new ("row_collapsed",
612                   G_TYPE_FROM_CLASS (object_class),
613                   G_SIGNAL_RUN_LAST,
614                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
615                   NULL, NULL,
616                   gtk_marshal_VOID__BOXED_BOXED,
617                   GTK_TYPE_NONE, 2,
618                   GTK_TYPE_TREE_ITER,
619                   GTK_TYPE_TREE_PATH);
620
621   tree_view_signals[COLUMNS_CHANGED] =
622     g_signal_new ("columns_changed",
623                   G_TYPE_FROM_CLASS (object_class),
624                   G_SIGNAL_RUN_LAST,
625                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
626                   NULL, NULL,
627                   gtk_marshal_NONE__NONE,
628                   G_TYPE_NONE, 0);
629
630   tree_view_signals[BEGIN_EXTENDED_SELECTION] =
631     g_signal_new ("begin_extended_selection",
632                   G_TYPE_FROM_CLASS (object_class),
633                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
634                   G_STRUCT_OFFSET (GtkTreeViewClass, begin_extended_selection),
635                   NULL, NULL,
636                   gtk_marshal_NONE__NONE,
637                   G_TYPE_NONE, 0);
638
639   tree_view_signals[END_EXTENDED_SELECTION] =
640     g_signal_new ("end_extended_selection",
641                   G_TYPE_FROM_CLASS (object_class),
642                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
643                   G_STRUCT_OFFSET (GtkTreeViewClass, end_extended_selection),
644                   NULL, NULL,
645                   gtk_marshal_NONE__NONE,
646                   G_TYPE_NONE, 0);
647
648   tree_view_signals[BEGIN_FREE_MOTION] =
649     g_signal_new ("begin_free_motion",
650                   G_TYPE_FROM_CLASS (object_class),
651                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
652                   G_STRUCT_OFFSET (GtkTreeViewClass, begin_free_motion),
653                   NULL, NULL,
654                   gtk_marshal_NONE__NONE,
655                   G_TYPE_NONE, 0);
656
657   tree_view_signals[END_FREE_MOTION] =
658     g_signal_new ("end_free_motion",
659                   G_TYPE_FROM_CLASS (object_class),
660                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
661                   G_STRUCT_OFFSET (GtkTreeViewClass, end_free_motion),
662                   NULL, NULL,
663                   gtk_marshal_NONE__NONE,
664                   G_TYPE_NONE, 0);
665
666   tree_view_signals[MOVE_CURSOR] =
667     g_signal_new ("move_cursor",
668                   G_TYPE_FROM_CLASS (object_class),
669                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
670                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
671                   NULL, NULL,
672                   gtk_marshal_VOID__ENUM_INT,
673                   GTK_TYPE_NONE, 2, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT);
674
675   tree_view_signals[SELECT_CURSOR_ROW] =
676     g_signal_new ("select_cursor_row",
677                   G_TYPE_FROM_CLASS (object_class),
678                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
679                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
680                   NULL, NULL,
681                   gtk_marshal_NONE__NONE,
682                   GTK_TYPE_NONE, 0);
683
684   tree_view_signals[TOGGLE_CURSOR_ROW] =
685     g_signal_new ("toggle_cursor_row",
686                   G_TYPE_FROM_CLASS (object_class),
687                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
688                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
689                   NULL, NULL,
690                   gtk_marshal_NONE__NONE,
691                   GTK_TYPE_NONE, 0);
692
693   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
694     g_signal_new ("expand_collapse_cursor_row",
695                   G_TYPE_FROM_CLASS (object_class),
696                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
697                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
698                   NULL, NULL,
699                   gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
700                   GTK_TYPE_NONE, 3, GTK_TYPE_BOOL, GTK_TYPE_BOOL, GTK_TYPE_BOOL);
701
702   tree_view_signals[SELECT_CURSOR_PARENT] =
703     g_signal_new ("select_cursor_parent",
704                   G_TYPE_FROM_CLASS (object_class),
705                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
706                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
707                   NULL, NULL,
708                   gtk_marshal_NONE__NONE,
709                   GTK_TYPE_NONE, 0);
710
711   /* Key bindings */
712   gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, 0, "begin_extended_selection", 0);
713   gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
714   gtk_binding_entry_add_signal (binding_set, GDK_Control_L, 0, "begin_free_motion", 0);
715   gtk_binding_entry_add_signal (binding_set, GDK_Control_L, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
716   gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, 0, "begin_extended_selection", 0);
717   gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
718   gtk_binding_entry_add_signal (binding_set, GDK_Control_R, 0, "begin_free_motion", 0);
719   gtk_binding_entry_add_signal (binding_set, GDK_Control_R, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
720
721   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
722                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
723
724   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
725                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
726
727   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
728                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
729
730   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
731                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
732
733   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
734                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
735
736   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
737                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
738
739   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
740                                   GTK_MOVEMENT_PAGES, -1);
741
742   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
743                                   GTK_MOVEMENT_PAGES, 1);
744
745   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
746                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
747                                 GTK_TYPE_INT, 1);
748
749   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
750                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
751                                 GTK_TYPE_INT, -1);
752
753   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "move_cursor", 2,
754                                 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
755                                 GTK_TYPE_INT, 1);
756
757   gtk_binding_entry_add_signal (binding_set, GDK_b, GDK_CONTROL_MASK, "move_cursor", 2,
758                                 GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
759                                 GTK_TYPE_INT, -1);
760
761   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
762
763   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 0);
764
765   /* expand and collapse rows */
766   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
767                                 GTK_TYPE_BOOL, FALSE,
768                                 GTK_TYPE_BOOL, TRUE,
769                                 GTK_TYPE_BOOL, FALSE);
770   /* Not doable on US keyboards */
771   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
772                                 GTK_TYPE_BOOL, FALSE,
773                                 GTK_TYPE_BOOL, TRUE,
774                                 GTK_TYPE_BOOL, TRUE);
775   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
776                                 GTK_TYPE_BOOL, FALSE,
777                                 GTK_TYPE_BOOL, TRUE,
778                                 GTK_TYPE_BOOL, FALSE);
779   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
780                                 GTK_TYPE_BOOL, FALSE,
781                                 GTK_TYPE_BOOL, TRUE,
782                                 GTK_TYPE_BOOL, TRUE);
783   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
784                                 GTK_TYPE_BOOL, FALSE,
785                                 GTK_TYPE_BOOL, TRUE,
786                                 GTK_TYPE_BOOL, TRUE);
787   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
788                                 GTK_TYPE_BOOL, TRUE,
789                                 GTK_TYPE_BOOL, TRUE,
790                                 GTK_TYPE_BOOL, TRUE);
791
792   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
793                                 GTK_TYPE_BOOL, FALSE,
794                                 GTK_TYPE_BOOL, FALSE,
795                                 GTK_TYPE_BOOL, FALSE);
796   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
797                                 GTK_TYPE_BOOL, FALSE,
798                                 GTK_TYPE_BOOL, FALSE,
799                                 GTK_TYPE_BOOL, TRUE);
800   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
801                                 GTK_TYPE_BOOL, FALSE,
802                                 GTK_TYPE_BOOL, FALSE,
803                                 GTK_TYPE_BOOL, FALSE);
804   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
805                                 GTK_TYPE_BOOL, FALSE,
806                                 GTK_TYPE_BOOL, FALSE,
807                                 GTK_TYPE_BOOL, TRUE);
808   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
809                                 GTK_TYPE_BOOL, FALSE,
810                                 GTK_TYPE_BOOL, FALSE,
811                                 GTK_TYPE_BOOL, TRUE);
812
813   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
814
815 }
816
817 static void
818 gtk_tree_view_init (GtkTreeView *tree_view)
819 {
820   tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
821
822   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
823
824   tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
825   gtk_widget_style_get (GTK_WIDGET (tree_view), "expander_width", &tree_view->priv->tab_offset, NULL);
826   tree_view->priv->n_columns = 0;
827   tree_view->priv->header_height = 1;
828   tree_view->priv->x_drag = 0;
829   tree_view->priv->drag_pos = -1;
830   tree_view->priv->header_has_focus = FALSE;
831   tree_view->priv->pressed_button = -1;
832   tree_view->priv->press_start_x = -1;
833   tree_view->priv->press_start_y = -1;
834   tree_view->priv->reorderable = FALSE;
835   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
836   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
837   _gtk_tree_view_update_size (tree_view);
838 }
839
840 \f
841
842 /* GObject Methods
843  */
844
845 static void
846 gtk_tree_view_set_property (GObject         *object,
847                             guint            prop_id,
848                             const GValue    *value,
849                             GParamSpec      *pspec)
850 {
851   GtkTreeView *tree_view;
852
853   tree_view = GTK_TREE_VIEW (object);
854
855   switch (prop_id)
856     {
857     case PROP_MODEL:
858       gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (g_value_get_object (value)));
859       break;
860     case PROP_HADJUSTMENT:
861       gtk_tree_view_set_hadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
862       break;
863     case PROP_VADJUSTMENT:
864       gtk_tree_view_set_vadjustment (tree_view, GTK_ADJUSTMENT (g_value_get_object (value)));
865       break;
866     case PROP_HEADERS_VISIBLE:
867       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
868       break;
869     case PROP_HEADERS_CLICKABLE:
870       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
871       break;
872     case PROP_EXPANDER_COLUMN:
873       gtk_tree_view_set_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (g_value_get_object (value)));
874       break;
875     case PROP_REORDERABLE:
876       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
877       break;
878     case PROP_RULES_HINT:
879       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
880       break;
881     default:
882       break;
883     }
884 }
885
886 static void
887 gtk_tree_view_get_property (GObject         *object,
888                             guint            prop_id,
889                             GValue          *value,
890                             GParamSpec      *pspec)
891 {
892   GtkTreeView *tree_view;
893
894   tree_view = GTK_TREE_VIEW (object);
895
896   switch (prop_id)
897     {
898     case PROP_MODEL:
899       g_value_set_object (value, G_OBJECT (tree_view->priv->model));
900       break;
901     case PROP_HADJUSTMENT:
902       g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
903       break;
904     case PROP_VADJUSTMENT:
905       g_value_set_object (value, G_OBJECT (tree_view->priv->vadjustment));
906       break;
907     case PROP_HEADERS_VISIBLE:
908       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
909       break;
910     case PROP_EXPANDER_COLUMN:
911       g_value_set_object (value, G_OBJECT (tree_view->priv->expander_column));
912       break;
913     case PROP_REORDERABLE:
914       g_value_set_boolean (value, tree_view->priv->reorderable);
915       break;
916     case PROP_RULES_HINT:
917       g_value_set_boolean (value, tree_view->priv->has_rules);
918       break;
919     default:
920       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
921       break;
922     }
923 }
924
925 static void
926 gtk_tree_view_finalize (GObject *object)
927 {
928   GtkTreeView *tree_view = (GtkTreeView *) object;
929
930   g_free (tree_view->priv);
931
932   if (G_OBJECT_CLASS (parent_class)->finalize)
933     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
934 }
935
936 \f
937
938 /* GtkObject Methods
939  */
940
941 static void
942 gtk_tree_view_destroy (GtkObject *object)
943 {
944   GtkTreeView *tree_view = (GtkTreeView *) object;
945   GList *list;
946
947
948   if (tree_view->priv->tree != NULL)
949     {
950       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
951       _gtk_rbtree_free (tree_view->priv->tree);
952       tree_view->priv->tree = NULL;
953     }
954
955   if (tree_view->priv->model != NULL)
956     {
957       g_object_unref (G_OBJECT (tree_view->priv->model));
958       tree_view->priv->model = NULL;
959     }
960
961   if (tree_view->priv->columns != NULL)
962     {
963       for (list = tree_view->priv->columns; list; list = list->next)
964         g_object_unref (G_OBJECT (list->data));
965       g_list_free (tree_view->priv->columns);
966       tree_view->priv->columns = NULL;
967     }
968
969   if (tree_view->priv->selection != NULL)
970     {
971       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
972       g_object_unref (tree_view->priv->selection);
973       tree_view->priv->selection = NULL;
974     }
975
976   if (tree_view->priv->scroll_to_path != NULL)
977     {
978       gtk_tree_path_free (tree_view->priv->scroll_to_path);
979       tree_view->priv->scroll_to_path = NULL;
980     }
981
982   if (tree_view->priv->drag_dest_row != NULL)
983     {
984       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
985       tree_view->priv->drag_dest_row = NULL;
986     }
987
988   
989   if (tree_view->priv->column_drop_func_data &&
990       tree_view->priv->column_drop_func_data_destroy)
991     {
992       (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
993       tree_view->priv->column_drop_func_data = NULL;
994     }
995
996   if (tree_view->priv->destroy_count_destroy &&
997       tree_view->priv->destroy_count_data)
998     {
999       (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
1000       tree_view->priv->destroy_count_data = NULL;
1001     }
1002
1003   gtk_tree_row_reference_free (tree_view->priv->cursor);
1004   tree_view->priv->cursor = NULL;
1005
1006   gtk_tree_row_reference_free (tree_view->priv->anchor);
1007   tree_view->priv->anchor = NULL;
1008
1009   if (GTK_OBJECT_CLASS (parent_class)->destroy)
1010     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1011 }
1012
1013 \f
1014
1015 /* GtkWidget Methods
1016  */
1017
1018 /* GtkWidget::map helper */
1019 static void
1020 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1021 {
1022   GList *list;
1023
1024   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1025
1026   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1027     {
1028       GtkTreeViewColumn *column;
1029
1030       for (list = tree_view->priv->columns; list; list = list->next)
1031         {
1032           column = list->data;
1033           if (GTK_WIDGET_VISIBLE (column->button) &&
1034               !GTK_WIDGET_MAPPED (column->button))
1035             gtk_widget_map (column->button);
1036         }
1037       for (list = tree_view->priv->columns; list; list = list->next)
1038         {
1039           column = list->data;
1040           if (column->visible == FALSE)
1041             continue;
1042           if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE)
1043             {
1044               gdk_window_raise (column->window);
1045               gdk_window_show (column->window);
1046             }
1047           else
1048             gdk_window_hide (column->window);
1049         }
1050       gdk_window_show (tree_view->priv->header_window);
1051     }
1052 }
1053
1054 static void
1055 gtk_tree_view_map (GtkWidget *widget)
1056 {
1057   GList *tmp_list;
1058   GtkTreeView *tree_view;
1059
1060   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1061
1062   tree_view = GTK_TREE_VIEW (widget);
1063
1064   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1065
1066   tmp_list = tree_view->priv->children;
1067   while (tmp_list)
1068     {
1069       GtkTreeViewChild *child = tmp_list->data;
1070       tmp_list = tmp_list->next;
1071
1072       if (GTK_WIDGET_VISIBLE (child->widget))
1073         {
1074           if (!GTK_WIDGET_MAPPED (child->widget))
1075             gtk_widget_map (child->widget);
1076         }
1077     }
1078   gdk_window_show (tree_view->priv->bin_window);
1079
1080   gtk_tree_view_map_buttons (tree_view);
1081
1082   gdk_window_show (widget->window);
1083 }
1084
1085 static void
1086 gtk_tree_view_realize (GtkWidget *widget)
1087 {
1088   GList *tmp_list;
1089   GtkTreeView *tree_view;
1090   GdkGCValues values;
1091   GdkWindowAttr attributes;
1092   gint attributes_mask;
1093
1094   g_return_if_fail (widget != NULL);
1095   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1096
1097   tree_view = GTK_TREE_VIEW (widget);
1098
1099   gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
1100   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1101
1102   /* Make the main, clipping window */
1103   attributes.window_type = GDK_WINDOW_CHILD;
1104   attributes.x = widget->allocation.x;
1105   attributes.y = widget->allocation.y;
1106   attributes.width = widget->allocation.width;
1107   attributes.height = widget->allocation.height;
1108   attributes.wclass = GDK_INPUT_OUTPUT;
1109   attributes.visual = gtk_widget_get_visual (widget);
1110   attributes.colormap = gtk_widget_get_colormap (widget);
1111   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1112
1113   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1114
1115   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1116                                    &attributes, attributes_mask);
1117   gdk_window_set_user_data (widget->window, widget);
1118
1119   /* Make the window for the tree */
1120   attributes.x = 0;
1121   attributes.y = 0;
1122   attributes.width = tree_view->priv->width;
1123   attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
1124   attributes.event_mask = GDK_EXPOSURE_MASK |
1125     GDK_SCROLL_MASK |
1126     GDK_POINTER_MOTION_MASK |
1127     GDK_ENTER_NOTIFY_MASK |
1128     GDK_LEAVE_NOTIFY_MASK |
1129     GDK_BUTTON_PRESS_MASK |
1130     GDK_BUTTON_RELEASE_MASK |
1131     gtk_widget_get_events (widget);
1132
1133   tree_view->priv->bin_window = gdk_window_new (widget->window,
1134                                                 &attributes, attributes_mask);
1135   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1136
1137   /* Make the column header window */
1138   attributes.x = 0;
1139   attributes.y = 0;
1140   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1141   attributes.height = tree_view->priv->header_height;
1142   attributes.event_mask = (GDK_EXPOSURE_MASK |
1143                            GDK_SCROLL_MASK |
1144                            GDK_BUTTON_PRESS_MASK |
1145                            GDK_BUTTON_RELEASE_MASK |
1146                            GDK_KEY_PRESS_MASK |
1147                            GDK_KEY_RELEASE_MASK) |
1148     gtk_widget_get_events (widget);
1149
1150   tree_view->priv->header_window = gdk_window_new (widget->window,
1151                                                    &attributes, attributes_mask);
1152   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1153
1154
1155   values.foreground = (widget->style->white.pixel==0 ?
1156                        widget->style->black:widget->style->white);
1157   values.function = GDK_XOR;
1158   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1159   tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
1160                                                     &values,
1161                                                     GDK_GC_FOREGROUND |
1162                                                     GDK_GC_FUNCTION |
1163                                                     GDK_GC_SUBWINDOW);
1164   /* Add them all up. */
1165   widget->style = gtk_style_attach (widget->style, widget->window);
1166   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1167   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1168   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1169
1170   tmp_list = tree_view->priv->children;
1171   while (tmp_list)
1172     {
1173       GtkTreeViewChild *child = tmp_list->data;
1174       tmp_list = tmp_list->next;
1175
1176       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1177     }
1178
1179   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1180     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1181
1182   _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1183
1184   if (tree_view->priv->scroll_to_path != NULL ||
1185       tree_view->priv->scroll_to_column != NULL)
1186     {
1187       gtk_tree_view_scroll_to_cell (tree_view,
1188                                     tree_view->priv->scroll_to_path,
1189                                     tree_view->priv->scroll_to_column,
1190                                     tree_view->priv->scroll_to_row_align,
1191                                     tree_view->priv->scroll_to_col_align);
1192       if (tree_view->priv->scroll_to_path)
1193         {
1194           gtk_tree_path_free (tree_view->priv->scroll_to_path);
1195           tree_view->priv->scroll_to_path = NULL;
1196         }
1197       tree_view->priv->scroll_to_column = NULL;
1198     }
1199 }
1200
1201 static void
1202 gtk_tree_view_unrealize (GtkWidget *widget)
1203 {
1204   GtkTreeView *tree_view;
1205   GList *list;
1206
1207   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1208
1209   tree_view = GTK_TREE_VIEW (widget);
1210
1211   if (tree_view->priv->scroll_timeout != 0)
1212     {
1213       gtk_timeout_remove (tree_view->priv->scroll_timeout);
1214       tree_view->priv->scroll_timeout = 0;
1215     }
1216
1217   if (tree_view->priv->open_dest_timeout != 0)
1218     {
1219       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
1220       tree_view->priv->open_dest_timeout = 0;
1221     }
1222
1223   for (list = tree_view->priv->columns; list; list = list->next)
1224     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1225
1226   gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
1227   gdk_window_destroy (tree_view->priv->bin_window);
1228   tree_view->priv->bin_window = NULL;
1229
1230   gdk_window_set_user_data (tree_view->priv->header_window, NULL);
1231   gdk_window_destroy (tree_view->priv->header_window);
1232   tree_view->priv->header_window = NULL;
1233
1234   if (tree_view->priv->drag_window)
1235     {
1236       gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
1237       gdk_window_destroy (tree_view->priv->drag_window);
1238       tree_view->priv->drag_window = NULL;
1239     }
1240
1241   if (tree_view->priv->drag_highlight_window)
1242     {
1243       gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
1244       gdk_window_destroy (tree_view->priv->drag_highlight_window);
1245       tree_view->priv->drag_highlight_window = NULL;
1246     }
1247
1248   if (tree_view->priv->cursor_drag)
1249     {
1250       gdk_cursor_destroy (tree_view->priv->cursor_drag);
1251       tree_view->priv->cursor_drag = NULL;
1252     }
1253
1254   if (tree_view->priv->xor_gc)
1255     {
1256       gdk_gc_destroy (tree_view->priv->xor_gc);
1257       tree_view->priv->xor_gc = NULL;
1258     }
1259
1260   /* GtkWidget::unrealize destroys children and widget->window */
1261   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1262     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1263 }
1264
1265 /* GtkWidget::size_request helper */
1266 static void
1267 gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
1268 {
1269   GList *list;
1270
1271   tree_view->priv->header_height = 1;
1272
1273   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
1274     {
1275       for (list = tree_view->priv->columns; list; list = list->next)
1276         {
1277           GtkRequisition requisition;
1278           GtkTreeViewColumn *column = list->data;
1279
1280           if (column->button == NULL)
1281             continue;
1282
1283           column = list->data;
1284
1285           gtk_widget_size_request (column->button, &requisition);
1286
1287           _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
1288           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1289         }
1290     }
1291 }
1292
1293 static void
1294 gtk_tree_view_size_request (GtkWidget      *widget,
1295                             GtkRequisition *requisition)
1296 {
1297   GtkTreeView *tree_view;
1298   GList *tmp_list;
1299
1300   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1301
1302   tree_view = GTK_TREE_VIEW (widget);
1303
1304   requisition->width = tree_view->priv->width;
1305   requisition->height = tree_view->priv->height + tree_view->priv->header_height;
1306
1307   tmp_list = tree_view->priv->children;
1308
1309   while (tmp_list)
1310     {
1311       GtkTreeViewChild *child = tmp_list->data;
1312       GtkRequisition child_requisition;
1313
1314       tmp_list = tmp_list->next;
1315
1316       if (GTK_WIDGET_VISIBLE (child->widget))
1317         gtk_widget_size_request (child->widget, &child_requisition);
1318     }
1319
1320   gtk_tree_view_size_request_buttons (tree_view);
1321 }
1322
1323 /* GtkWidget::size_allocate helper */
1324 static void
1325 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
1326 {
1327   GtkTreeView *tree_view;
1328   GList *list;
1329   GtkTreeViewColumn *column;
1330   GtkAllocation allocation;
1331   gint width = 0;
1332
1333   tree_view = GTK_TREE_VIEW (widget);
1334
1335   allocation.y = 0;
1336   allocation.height = tree_view->priv->header_height;
1337
1338   for (list = tree_view->priv->columns; list != NULL; list = list->next)
1339     {
1340       column = list->data;
1341
1342       if (!column->visible)
1343         continue;
1344
1345       allocation.x = width;
1346       allocation.width = column->displayed_width;
1347       width += column->width;
1348       gtk_widget_size_allocate (column->button, &allocation);
1349
1350       if (column->window)
1351         gdk_window_move_resize (column->window,
1352                                 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
1353                                 allocation.y,
1354                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
1355     }
1356 }
1357
1358 static void
1359 gtk_tree_view_size_allocate (GtkWidget     *widget,
1360                              GtkAllocation *allocation)
1361 {
1362   GList *tmp_list;
1363   GtkTreeView *tree_view;
1364
1365   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1366
1367   widget->allocation = *allocation;
1368
1369   tree_view = GTK_TREE_VIEW (widget);
1370
1371   gtk_tree_view_check_dirty (tree_view);
1372
1373   tmp_list = tree_view->priv->children;
1374
1375   while (tmp_list)
1376     {
1377       GtkAllocation allocation;
1378       GtkRequisition requisition;
1379
1380       GtkTreeViewChild *child = tmp_list->data;
1381       tmp_list = tmp_list->next;
1382
1383       allocation.x = child->x;
1384       allocation.y = child->y;
1385       gtk_widget_get_child_requisition (child->widget, &requisition);
1386       allocation.width = requisition.width;
1387       allocation.height = requisition.height;
1388
1389       gtk_widget_size_allocate (child->widget, &allocation);
1390     }
1391
1392   if (GTK_WIDGET_REALIZED (widget))
1393     {
1394       gdk_window_move_resize (widget->window,
1395                               allocation->x, allocation->y,
1396                               allocation->width, allocation->height);
1397       gdk_window_resize (tree_view->priv->header_window,
1398                          MAX (tree_view->priv->width, allocation->width),
1399                          tree_view->priv->header_height);
1400       if (tree_view->priv->width < allocation->width)
1401           gdk_window_resize (tree_view->priv->bin_window,
1402                              allocation->width,
1403                              tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
1404
1405       _gtk_tree_view_update_col_width (tree_view);
1406     }
1407
1408   gtk_tree_view_size_allocate_buttons (widget);
1409
1410   tree_view->priv->hadjustment->page_size = allocation->width;
1411   tree_view->priv->hadjustment->page_increment = allocation->width;
1412   tree_view->priv->hadjustment->step_increment = allocation->width / 10;
1413   tree_view->priv->hadjustment->lower = 0;
1414   tree_view->priv->hadjustment->upper = tree_view->priv->width;
1415
1416   if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
1417     tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
1418   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
1419
1420   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
1421   tree_view->priv->vadjustment->step_increment = (tree_view->priv->vadjustment->page_size) / 10;
1422   tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
1423   tree_view->priv->vadjustment->lower = 0;
1424   tree_view->priv->vadjustment->upper = tree_view->priv->height;
1425
1426   if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
1427     gtk_adjustment_set_value (tree_view->priv->vadjustment,
1428                               MAX (tree_view->priv->height - allocation->height, 0));
1429
1430   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
1431
1432 }
1433
1434 static gboolean
1435 gtk_tree_view_button_press (GtkWidget      *widget,
1436                             GdkEventButton *event)
1437 {
1438   GtkTreeView *tree_view;
1439   GList *list;
1440   GtkTreeViewColumn *column = NULL;
1441   gint i;
1442   GdkRectangle background_area;
1443   GdkRectangle cell_area;
1444   gint vertical_separator;
1445
1446   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1447   g_return_val_if_fail (event != NULL, FALSE);
1448
1449   tree_view = GTK_TREE_VIEW (widget);
1450   gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
1451
1452   if (event->window == tree_view->priv->bin_window)
1453     {
1454       GtkRBNode *node;
1455       GtkRBTree *tree;
1456       GtkTreePath *path;
1457       gchar *path_string;
1458       gint depth;
1459       gint new_y;
1460       gint y_offset;
1461       GtkTreeViewColumn *column = NULL;
1462
1463       if (!GTK_WIDGET_HAS_FOCUS (widget))
1464         gtk_widget_grab_focus (widget);
1465       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1466
1467       /* are we in an arrow? */
1468       if (tree_view->priv->prelight_node &&
1469           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1470         {
1471           if (event->button == 1)
1472             {
1473               gtk_grab_add (widget);
1474               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1475               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1476               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1477                                         tree_view->priv->prelight_tree,
1478                                         tree_view->priv->prelight_node,
1479                                         event->x,
1480                                         event->y);
1481             }
1482           return TRUE;
1483         }
1484
1485       /* find the node that was clicked */
1486       new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1487       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1488                                            TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
1489                                            &tree,
1490                                            &node) + new_y - (gint)event->y;
1491
1492       if (node == NULL)
1493         /* We clicked in dead space */
1494         return TRUE;
1495
1496       /* Get the path and the node */
1497       path = _gtk_tree_view_find_path (tree_view, tree, node);
1498       depth = gtk_tree_path_get_depth (path);
1499       background_area.y = y_offset + event->y + vertical_separator;
1500       background_area.height = GTK_RBNODE_GET_HEIGHT (node) - vertical_separator;
1501       background_area.x = 0;
1502
1503       /* Let the column have a chance at selecting it. */
1504       for (list = tree_view->priv->columns; list; list = list->next)
1505         {
1506           GtkTreeIter iter;
1507
1508           column = list->data;
1509
1510           if (!column->visible)
1511             continue;
1512
1513           background_area.width = column->displayed_width;
1514           if (gtk_tree_view_is_expander_column (tree_view, column) &&
1515               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1516             {
1517               cell_area = background_area;
1518               cell_area.x += depth*tree_view->priv->tab_offset;
1519               cell_area.width -= depth*tree_view->priv->tab_offset;
1520             }
1521           else
1522             {
1523               cell_area = background_area;
1524             }
1525
1526           if ((background_area.x > (gint) event->x) ||
1527               (background_area.y > (gint) event->y) ||
1528               (background_area.x + background_area.width <= (gint) event->x) ||
1529               (background_area.y + background_area.height <= (gint) event->y))
1530             {
1531               background_area.x += background_area.width;
1532               continue;
1533             }
1534
1535           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1536           gtk_tree_view_column_cell_set_cell_data (column,
1537                                                    tree_view->priv->model,
1538                                                    &iter);
1539
1540           path_string = gtk_tree_path_to_string (path);
1541
1542           if (gtk_tree_view_column_cell_event (column,
1543                                                (GdkEvent *)event,
1544                                                path_string,
1545                                                &background_area,
1546                                                &cell_area, 0))
1547             {
1548               g_free (path_string);
1549               gtk_tree_path_free (path);
1550               return TRUE;
1551             }
1552           else
1553             {
1554               g_free (path_string);
1555               break;
1556             }
1557         }
1558
1559       if (column == NULL)
1560         return FALSE;
1561
1562       /* The columns didn't want the event.  We handle it */
1563
1564       /* Save press to possibly begin a drag
1565        */
1566       if (tree_view->priv->pressed_button < 0)
1567         {
1568           tree_view->priv->pressed_button = event->button;
1569           tree_view->priv->press_start_x = event->x;
1570           tree_view->priv->press_start_y = event->y;
1571         }
1572
1573       gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
1574
1575       if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1576         {
1577           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
1578             {
1579               if (node->children == NULL)
1580                 gtk_tree_view_real_expand_row (tree_view, path,
1581                                                tree, node, FALSE);
1582               else
1583                 gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1584                                                  tree, node);
1585             }
1586           gtk_tree_view_row_activated (tree_view, path, column);
1587
1588         }
1589       gtk_tree_path_free (path);
1590       return TRUE;
1591     }
1592
1593   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
1594    */
1595   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1596     {
1597       column = list->data;
1598       if (event->window == column->window &&
1599           column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE &&
1600           column->window)
1601         {
1602           gpointer drag_data;
1603
1604           if (gdk_pointer_grab (column->window, FALSE,
1605                                 GDK_POINTER_MOTION_HINT_MASK |
1606                                 GDK_BUTTON1_MOTION_MASK |
1607                                 GDK_BUTTON_RELEASE_MASK,
1608                                 NULL, NULL, event->time))
1609             return FALSE;
1610
1611           gtk_grab_add (widget);
1612           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1613
1614           /* block attached dnd signal handler */
1615           drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1616           if (drag_data)
1617             gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1618
1619           if (!GTK_WIDGET_HAS_FOCUS (widget))
1620             gtk_widget_grab_focus (widget);
1621
1622           tree_view->priv->drag_pos = i;
1623           tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1624         }
1625     }
1626   return TRUE;
1627 }
1628
1629 /* GtkWidget::button_release_event helper */
1630 static gboolean
1631 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
1632                                           GdkEventButton *event)
1633 {
1634   GtkTreeView *tree_view;
1635   GtkAllocation allocation;
1636
1637   tree_view = GTK_TREE_VIEW (widget);
1638
1639   allocation = tree_view->priv->drag_column->button->allocation;
1640   allocation.x = tree_view->priv->drag_column_x;
1641   gdk_pointer_ungrab (GDK_CURRENT_TIME);
1642   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
1643   gdk_window_reparent (tree_view->priv->drag_column->button->window,
1644                        tree_view->priv->header_window,
1645                        tree_view->priv->drag_column_x,
1646                        tree_view->priv->drag_column->button->allocation.y);
1647   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
1648
1649   gtk_widget_size_allocate (tree_view->priv->drag_column->button, &allocation);
1650   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
1651
1652   if (tree_view->priv->cur_reorder &&
1653       tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
1654     gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
1655                                      tree_view->priv->cur_reorder->left_column);
1656   tree_view->priv->drag_column = NULL;
1657   gdk_window_hide (tree_view->priv->drag_window);
1658
1659   g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
1660   g_list_free (tree_view->priv->column_drag_info);
1661   tree_view->priv->column_drag_info = NULL;
1662
1663   gdk_window_hide (tree_view->priv->drag_highlight_window);
1664
1665   /* Reset our flags */
1666   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
1667   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
1668
1669   return TRUE;
1670 }
1671
1672 /* GtkWidget::button_release_event helper */
1673 static gboolean
1674 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
1675                                             GdkEventButton *event)
1676 {
1677   GtkTreeView *tree_view;
1678   gpointer drag_data;
1679   gint width;
1680   gint x;
1681   gint i;
1682
1683   tree_view = GTK_TREE_VIEW (widget);
1684
1685   i = tree_view->priv->drag_pos;
1686   tree_view->priv->drag_pos = -1;
1687
1688       /* unblock attached dnd signal handler */
1689   drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1690   if (drag_data)
1691     gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1692
1693   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1694   gtk_widget_get_pointer (widget, &x, NULL);
1695   gtk_grab_remove (widget);
1696   gdk_pointer_ungrab (event->time);
1697
1698   width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1699   _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1700
1701   return TRUE;
1702 }
1703
1704 static gboolean
1705 gtk_tree_view_button_release (GtkWidget      *widget,
1706                               GdkEventButton *event)
1707 {
1708   GtkTreeView *tree_view;
1709
1710   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1711   g_return_val_if_fail (event != NULL, FALSE);
1712
1713   tree_view = GTK_TREE_VIEW (widget);
1714
1715   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
1716     return gtk_tree_view_button_release_drag_column (widget, event);
1717
1718   if (tree_view->priv->pressed_button == event->button)
1719     tree_view->priv->pressed_button = -1;
1720
1721   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1722     return gtk_tree_view_button_release_column_resize (widget, event);
1723
1724   if (tree_view->priv->button_pressed_node == NULL)
1725     return FALSE;
1726
1727   if (event->button == 1)
1728     {
1729       gtk_grab_remove (widget);
1730       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
1731           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1732         {
1733           GtkTreePath *path = NULL;
1734
1735           path = _gtk_tree_view_find_path (tree_view,
1736                                            tree_view->priv->button_pressed_tree,
1737                                            tree_view->priv->button_pressed_node);
1738           /* Actually activate the node */
1739           if (tree_view->priv->button_pressed_node->children == NULL)
1740             gtk_tree_view_real_expand_row (tree_view, path,
1741                                            tree_view->priv->button_pressed_tree,
1742                                            tree_view->priv->button_pressed_node,
1743                                            FALSE);
1744           else
1745             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
1746                                              tree_view->priv->button_pressed_tree,
1747                                              tree_view->priv->button_pressed_node);
1748           gtk_tree_path_free (path);
1749         }
1750
1751       tree_view->priv->button_pressed_tree = NULL;
1752       tree_view->priv->button_pressed_node = NULL;
1753     }
1754
1755   return TRUE;
1756 }
1757
1758
1759 /* GtkWidget::motion_event function set.
1760  */
1761
1762 static gboolean
1763 coords_are_over_arrow (GtkTreeView *tree_view,
1764                        GtkRBTree   *tree,
1765                        GtkRBNode   *node,
1766                        /* these are in tree window coords */
1767                        gint         x,
1768                        gint         y)
1769 {
1770   GdkRectangle arrow;
1771   gint x2;
1772
1773   if (!GTK_WIDGET_REALIZED (tree_view))
1774     return FALSE;
1775
1776   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
1777     return FALSE;
1778
1779   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
1780
1781   arrow.height = BACKGROUND_HEIGHT (node);
1782
1783   gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
1784
1785   arrow.width = x2 - arrow.x;
1786
1787   return (x >= arrow.x &&
1788           x < (arrow.x + arrow.height) &&
1789           y >= arrow.y &&
1790           y < (arrow.y + arrow.height));
1791 }
1792
1793 static void
1794 do_unprelight (GtkTreeView *tree_view,
1795                /* these are in tree window coords */
1796                gint x,
1797                gint y)
1798 {
1799   if (tree_view->priv->prelight_node == NULL)
1800     return;
1801
1802   GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1803
1804   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
1805       !coords_are_over_arrow (tree_view,
1806                               tree_view->priv->prelight_tree,
1807                               tree_view->priv->prelight_node,
1808                               x,
1809                               y))
1810     /* We need to unprelight the old arrow. */
1811     {
1812       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1813
1814       gtk_tree_view_draw_arrow (tree_view,
1815                                 tree_view->priv->prelight_tree,
1816                                 tree_view->priv->prelight_node,
1817                                 x,
1818                                 y);
1819
1820     }
1821
1822   tree_view->priv->prelight_node = NULL;
1823   tree_view->priv->prelight_tree = NULL;
1824 }
1825
1826 static void
1827 do_prelight (GtkTreeView *tree_view,
1828              GtkRBTree   *tree,
1829              GtkRBNode   *node,
1830              /* these are in tree window coords */
1831              gint         x,
1832              gint         y)
1833 {
1834   if (coords_are_over_arrow (tree_view, tree, node, x, y))
1835     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1836
1837   tree_view->priv->prelight_node = node;
1838   tree_view->priv->prelight_tree = tree;
1839
1840   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1841 }
1842
1843 static void
1844 ensure_unprelighted (GtkTreeView *tree_view)
1845 {
1846   do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
1847   g_assert (tree_view->priv->prelight_node == NULL);
1848 }
1849
1850
1851
1852 /* Our motion arrow is either a box (in the case of the original spot)
1853  * or an arrow.  It is expander_width wide.
1854  */
1855 /*
1856  * 11111111111111
1857  * 01111111111110
1858  * 00111111111100
1859  * 00011111111000
1860  * 00001111110000
1861  * 00000111100000
1862  * 00000111100000
1863  * 00000111100000
1864  * ~ ~ ~ ~ ~ ~ ~
1865  * 00000111100000
1866  * 00000111100000
1867  * 00000111100000
1868  * 00001111110000
1869  * 00011111111000
1870  * 00111111111100
1871  * 01111111111110
1872  * 11111111111111
1873  */
1874
1875 static void
1876 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
1877 {
1878   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
1879   GtkWidget *widget = GTK_WIDGET (tree_view);
1880   GdkBitmap *mask = NULL;
1881   gint x;
1882   gint y;
1883   gint width;
1884   gint height;
1885   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
1886   GdkWindowAttr attributes;
1887   guint attributes_mask;
1888
1889   if (!reorder ||
1890       reorder->left_column == tree_view->priv->drag_column ||
1891       reorder->right_column == tree_view->priv->drag_column)
1892     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
1893   else if (reorder->left_column || reorder->right_column)
1894     {
1895       GdkRectangle visible_rect;
1896       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
1897       if (reorder->left_column)
1898         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
1899       else
1900         x = reorder->right_column->button->allocation.x;
1901       if (x < visible_rect.x)
1902         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
1903       else if (x > visible_rect.x + visible_rect.width)
1904         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
1905       else
1906         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
1907     }
1908
1909   /* We want to draw the rectangle over the initial location. */
1910   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
1911     {
1912       GdkGC *gc;
1913       GdkColor col;
1914
1915       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
1916         {
1917
1918           if (tree_view->priv->drag_highlight_window)
1919             gdk_window_destroy (tree_view->priv->drag_highlight_window);
1920
1921           attributes.window_type = GDK_WINDOW_CHILD;
1922           attributes.wclass = GDK_INPUT_OUTPUT;
1923           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1924           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1925           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
1926           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1927           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
1928           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
1929
1930           width = tree_view->priv->drag_column->button->allocation.width;
1931           height = tree_view->priv->drag_column->button->allocation.height;
1932           gdk_window_move_resize (tree_view->priv->drag_highlight_window,
1933                                   tree_view->priv->drag_column_x, 0, width, height);
1934
1935           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
1936           gc = gdk_gc_new (mask);
1937           col.pixel = 1;
1938           gdk_gc_set_foreground (gc, &col);
1939           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
1940           col.pixel = 0;
1941           gdk_gc_set_foreground(gc, &col);
1942           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
1943           gdk_gc_destroy (gc);
1944
1945           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
1946                                          mask, 0, 0);
1947           if (mask) gdk_pixmap_unref (mask);
1948           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
1949         }
1950     }
1951   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
1952     {
1953       gint i, j = 1;
1954       GdkGC *gc;
1955       GdkColor col;
1956       gint expander_width;
1957
1958       gtk_widget_style_get (widget,
1959                             "expander_height", &width,
1960                             "expander_width", &expander_width,
1961                             NULL);
1962
1963       /* Get x, y, width, height of arrow */
1964       if (reorder->left_column)
1965         {
1966           gdk_window_get_origin (reorder->left_column->button->window, &x, &y);
1967           x += reorder->left_column->button->allocation.width - width/2;
1968           height = reorder->left_column->button->allocation.height;
1969         }
1970       else
1971         {
1972           gdk_window_get_origin (reorder->right_column->button->window, &x, &y);
1973           x -= width/2;
1974           height = reorder->right_column->button->allocation.height;
1975         }
1976       y -= expander_width/2; /* The arrow takes up only half the space */
1977       height += expander_width;
1978
1979       /* Create the new window */
1980       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
1981         {
1982           if (tree_view->priv->drag_highlight_window)
1983             gdk_window_destroy (tree_view->priv->drag_highlight_window);
1984
1985           attributes.window_type = GDK_WINDOW_TEMP;
1986           attributes.wclass = GDK_INPUT_OUTPUT;
1987           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1988           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1989           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
1990           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1991           attributes.width = width;
1992           attributes.height = height;
1993           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
1994           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
1995
1996           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
1997           gc = gdk_gc_new (mask);
1998           col.pixel = 1;
1999           gdk_gc_set_foreground (gc, &col);
2000           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2001
2002           /* Draw the 2 arrows as per above */
2003           col.pixel = 0;
2004           gdk_gc_set_foreground (gc, &col);
2005           for (i = 0; i < width; i ++)
2006             {
2007               if (i == (width/2 - 1))
2008                 continue;
2009               gdk_draw_line (mask, gc, i, j, i, height - j);
2010               if (i < (width/2 - 1))
2011                 j++;
2012               else
2013                 j--;
2014             }
2015           gdk_gc_destroy (gc);
2016           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2017                                          mask, 0, 0);
2018           if (mask) gdk_pixmap_unref (mask);
2019         }
2020
2021       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
2022       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2023     }
2024   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
2025            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2026     {
2027       gint i, j = 1;
2028       GdkGC *gc;
2029       GdkColor col;
2030       gint expander_height;
2031
2032       gtk_widget_style_get (widget,
2033                             "expander_height", &expander_height,
2034                             "expander_width", &width,
2035                             NULL);
2036
2037       /* Get x, y, width, height of arrow */
2038       width = width/2; /* remember, the arrow only takes half the available width */
2039       gdk_window_get_origin (widget->window, &x, &y);
2040       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2041         x += widget->allocation.width - width;
2042
2043       if (reorder->left_column)
2044         height = reorder->left_column->button->allocation.height;
2045       else
2046         height = reorder->right_column->button->allocation.height;
2047
2048       y -= expander_height;
2049       height += 2*expander_height;
2050
2051       /* Create the new window */
2052       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
2053           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2054         {
2055           if (tree_view->priv->drag_highlight_window)
2056             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2057
2058           attributes.window_type = GDK_WINDOW_TEMP;
2059           attributes.wclass = GDK_INPUT_OUTPUT;
2060           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2061           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2062           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2063           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2064           attributes.width = width;
2065           attributes.height = height;
2066           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2067           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2068
2069           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2070           gc = gdk_gc_new (mask);
2071           col.pixel = 1;
2072           gdk_gc_set_foreground (gc, &col);
2073           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2074
2075           /* Draw the 2 arrows as per above */
2076           col.pixel = 0;
2077           gdk_gc_set_foreground (gc, &col);
2078           j = expander_height;
2079           for (i = 0; i < width; i ++)
2080             {
2081               gint k;
2082               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
2083                 k = width - i - 1;
2084               else
2085                 k = i;
2086               gdk_draw_line (mask, gc, k, j, k, height - j);
2087               gdk_draw_line (mask, gc, k, 0, k, expander_height - j);
2088               gdk_draw_line (mask, gc, k, height, k, height - expander_height + j);
2089               j--;
2090             }
2091           gdk_gc_destroy (gc);
2092           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2093                                          mask, 0, 0);
2094           if (mask) gdk_pixmap_unref (mask);
2095         }
2096
2097       tree_view->priv->drag_column_window_state = arrow_type;
2098       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2099    }
2100   else
2101     {
2102       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
2103       gdk_window_hide (tree_view->priv->drag_highlight_window);
2104       return;
2105     }
2106
2107   gdk_window_show (tree_view->priv->drag_highlight_window);
2108   gdk_window_raise (tree_view->priv->drag_highlight_window);
2109 }
2110
2111 static gboolean
2112 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
2113                                     GdkEventMotion *event)
2114 {
2115   gint x;
2116   gint new_width;
2117
2118   if (event->is_hint || event->window != widget->window)
2119     gtk_widget_get_pointer (widget, &x, NULL);
2120   else
2121     x = event->x;
2122
2123   new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget),
2124                                               GTK_TREE_VIEW (widget)->priv->drag_pos, &x);
2125   if (x != GTK_TREE_VIEW (widget)->priv->x_drag)
2126     _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
2127
2128   /* FIXME: Do we need to scroll */
2129   _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2130   return FALSE;
2131 }
2132
2133
2134 static void
2135 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
2136 {
2137   GtkTreeViewColumnReorder *reorder = NULL;
2138   GList *list;
2139   gint mouse_x;
2140
2141   gdk_window_get_pointer (tree_view->priv->bin_window, &mouse_x, NULL, NULL);
2142
2143   for (list = tree_view->priv->column_drag_info; list; list = list->next)
2144     {
2145       reorder = (GtkTreeViewColumnReorder *) list->data;
2146       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
2147         break;
2148       reorder = NULL;
2149     }
2150
2151   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
2152       return;*/
2153
2154   tree_view->priv->cur_reorder = reorder;
2155   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
2156 }
2157
2158 static gboolean
2159 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
2160 {
2161   GdkRectangle visible_rect;
2162   gint x;
2163   gint offset;
2164   gfloat value;
2165
2166   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
2167
2168   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2169
2170   /* See if we are near the edge. */
2171   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
2172   if (offset > 0)
2173     {
2174       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
2175       if (offset < 0)
2176         return TRUE;
2177     }
2178   offset = offset/3;
2179
2180   value = CLAMP (tree_view->priv->hadjustment->value + offset,
2181                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
2182   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
2183
2184   return TRUE;
2185
2186 }
2187
2188 static gboolean
2189 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
2190                                   GdkEventMotion *event)
2191 {
2192   GtkTreeView *tree_view = (GtkTreeView *) widget;
2193   GtkTreeViewColumn *column = tree_view->priv->drag_column;
2194   gint x, y;
2195
2196   /* Sanity Check */
2197   if ((column == NULL) ||
2198       (event->window != tree_view->priv->drag_window))
2199     return FALSE;
2200
2201   /* Handle moving the header */
2202   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
2203   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
2204              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
2205   gdk_window_move (tree_view->priv->drag_window, x, y);
2206
2207   /* autoscroll, if needed */
2208   gtk_tree_view_horizontal_autoscroll (tree_view);
2209   /* Update the current reorder position and arrow; */
2210   gtk_tree_view_update_current_reorder (tree_view);
2211
2212   return TRUE;
2213 }
2214
2215 static gboolean
2216 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
2217                                  GdkEventMotion *event)
2218 {
2219   GtkTreeView *tree_view;
2220   GtkRBTree *tree;
2221   GtkRBNode *node;
2222   gint new_y;
2223   GtkRBTree *old_prelight_tree;
2224   GtkRBNode *old_prelight_node;
2225
2226   tree_view = (GtkTreeView *) widget;
2227
2228   if (tree_view->priv->tree == NULL)
2229     return FALSE;
2230
2231   gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
2232
2233   old_prelight_tree = tree_view->priv->prelight_tree;
2234   old_prelight_node = tree_view->priv->prelight_node;
2235
2236   do_unprelight (tree_view, event->x, event->y);
2237
2238   new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2239
2240   _gtk_rbtree_find_offset (tree_view->priv->tree,
2241                            TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2242                            &tree,
2243                            &node);
2244
2245   if (tree == NULL)
2246     return TRUE;
2247
2248   /* If we are currently pressing down a button, we don't want to prelight anything else. */
2249   if ((tree_view->priv->button_pressed_node != NULL) &&
2250       (tree_view->priv->button_pressed_node != node))
2251     return TRUE;
2252
2253
2254   do_prelight (tree_view, tree, node, event->x, new_y);
2255
2256   if (old_prelight_node != tree_view->priv->prelight_node)
2257     {
2258       if (old_prelight_node)
2259         gtk_tree_view_queue_draw_node (tree_view,
2260                                        old_prelight_tree,
2261                                        old_prelight_node,
2262                                        NULL);
2263
2264       if (tree_view->priv->prelight_node)
2265         gtk_tree_view_queue_draw_node (tree_view,
2266                                        tree_view->priv->prelight_tree,
2267                                        tree_view->priv->prelight_node,
2268                                        NULL);
2269     }
2270
2271   return TRUE;
2272 }
2273
2274 static gboolean
2275 gtk_tree_view_motion (GtkWidget      *widget,
2276                       GdkEventMotion *event)
2277 {
2278   GtkTreeView *tree_view;
2279
2280   tree_view = (GtkTreeView *) widget;
2281
2282   /* Resizing a column */
2283   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2284     return gtk_tree_view_motion_resize_column (widget, event);
2285
2286   /* Drag column */
2287   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2288     return gtk_tree_view_motion_drag_column (widget, event);
2289
2290   /* Sanity check it */
2291   if (event->window == tree_view->priv->bin_window)
2292     return gtk_tree_view_motion_bin_window (widget, event);
2293
2294   return FALSE;
2295 }
2296
2297 /* Draws the focus rectangle around the cursor row */
2298 static void
2299 gtk_tree_view_draw_focus (GtkWidget *widget)
2300 {
2301   GtkTreeView *tree_view;
2302   GtkTreePath *cursor_path;
2303   GtkRBTree *tree = NULL;
2304   GtkRBNode *node = NULL;
2305   gint x, y;
2306   gint width, height;
2307   gint vertical_separator;
2308
2309   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2310
2311   tree_view = GTK_TREE_VIEW (widget);
2312
2313   gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2314
2315   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
2316     return;
2317
2318   if (! gtk_tree_row_reference_valid (tree_view->priv->cursor))
2319     return;
2320
2321   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2322
2323   _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
2324
2325   if (tree == NULL)
2326     {
2327       gtk_tree_path_free (cursor_path);
2328       return;
2329     }
2330
2331   gdk_drawable_get_size (tree_view->priv->bin_window,
2332                          &width, NULL);
2333
2334
2335   x = 0;
2336   y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2337   gdk_drawable_get_size (tree_view->priv->bin_window,
2338                          &width, NULL);
2339   width = width - 1;
2340   height = BACKGROUND_HEIGHT (node) - 1;
2341   if (tree_view->priv->focus_column != NULL)
2342     {
2343       GtkTreeIter iter;
2344
2345       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
2346       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column, tree_view->priv->model, &iter);
2347
2348       if (gtk_tree_view_column_cell_can_focus (tree_view->priv->focus_column))
2349         {
2350           GdkRectangle cell_area;
2351           gint x_offset;
2352           gint y_offset;
2353
2354           cell_area.x = tree_view->priv->focus_column->button->allocation.x;
2355           cell_area.y = y;
2356           cell_area.width = tree_view->priv->focus_column->displayed_width;
2357           cell_area.height = CELL_HEIGHT (node, vertical_separator);
2358
2359           gtk_tree_view_column_cell_get_size (tree_view->priv->focus_column,
2360                                               &cell_area, &x_offset, &y_offset, &width, &height);
2361
2362           width += 2;
2363           height += 2;
2364           x = cell_area.x + x_offset - 1;
2365           y = cell_area.y + y_offset - 1 + vertical_separator/2;
2366         }
2367     }
2368
2369   gtk_paint_focus (widget->style,
2370                    tree_view->priv->bin_window,
2371                    NULL,
2372                    widget,
2373                    "add-mode",
2374                    x, y, width, height);
2375
2376   gtk_tree_path_free (cursor_path);
2377 }
2378
2379 /* Warning: Very scary function.
2380  * Modify at your own risk
2381  */
2382 static gboolean
2383 gtk_tree_view_bin_expose (GtkWidget      *widget,
2384                           GdkEventExpose *event)
2385 {
2386   GtkTreeView *tree_view;
2387   GtkTreePath *path;
2388   GtkRBTree *tree;
2389   GList *list;
2390   GtkRBNode *node;
2391   GtkRBNode *cursor = NULL;
2392   GtkRBTree *cursor_tree = NULL;
2393   GtkRBNode *drag_highlight = NULL;
2394   GtkRBTree *drag_highlight_tree = NULL;
2395   GtkTreeIter iter;
2396   gint new_y;
2397   gint y_offset, x_offset, cell_offset;
2398   gint max_height;
2399   gint depth;
2400   GdkRectangle background_area;
2401   GdkRectangle cell_area;
2402   guint flags;
2403   gint highlight_x;
2404   gint bin_window_width;
2405   GtkTreePath *cursor_path;
2406   GtkTreePath *drag_dest_path;
2407   GList *last_column;
2408   gint vertical_separator;
2409
2410   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2411
2412   tree_view = GTK_TREE_VIEW (widget);
2413   gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
2414
2415   if (tree_view->priv->tree == NULL)
2416     return TRUE;
2417
2418   gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
2419   /* we want to account for a potential HEADER offset.
2420    * That is, if the header exists, we want to offset our event by its
2421    * height to find the right node.
2422    */
2423   new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
2424
2425   /* y_offset is the */
2426
2427   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
2428                                        TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2429                                        &tree,
2430                                        &node) + new_y - event->area.y;
2431   if (node == NULL)
2432     return TRUE;
2433
2434   /* find the path for the node */
2435   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
2436                                    tree,
2437                                    node);
2438   gtk_tree_model_get_iter (tree_view->priv->model,
2439                            &iter,
2440                            path);
2441   depth = gtk_tree_path_get_depth (path);
2442   gtk_tree_path_free (path);
2443
2444   cursor_path = NULL;
2445   drag_dest_path = NULL;
2446
2447   if (tree_view->priv->cursor)
2448     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2449
2450   if (cursor_path)
2451     _gtk_tree_view_find_node (tree_view, cursor_path,
2452                               &cursor_tree, &cursor);
2453
2454   if (tree_view->priv->drag_dest_row)
2455     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
2456
2457   if (drag_dest_path)
2458     _gtk_tree_view_find_node (tree_view, drag_dest_path,
2459                               &drag_highlight_tree, &drag_highlight);
2460
2461   gdk_drawable_get_size (tree_view->priv->bin_window,
2462                          &bin_window_width, NULL);
2463
2464   for (last_column = g_list_last (tree_view->priv->columns);
2465        last_column &&
2466          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2467          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2468        last_column = last_column->prev)
2469     ;
2470
2471   /* Actually process the expose event.  To do this, we want to
2472    * start at the first node of the event, and walk the tree in
2473    * order, drawing each successive node.
2474    */
2475
2476   do
2477     {
2478       gboolean parity;
2479
2480       max_height = BACKGROUND_HEIGHT (node);
2481
2482       x_offset = -event->area.x;
2483       cell_offset = 0;
2484       highlight_x = 0; /* should match x coord of first cell */
2485
2486       background_area.y = y_offset + event->area.y;
2487       background_area.height = max_height;
2488       flags = 0;
2489
2490       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
2491         flags |= GTK_CELL_RENDERER_PRELIT;
2492
2493       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
2494         flags |= GTK_CELL_RENDERER_SELECTED;
2495
2496       parity = _gtk_rbtree_node_find_parity (tree, node);
2497       
2498       for (list = tree_view->priv->columns; list; list = list->next)
2499         {
2500           GtkTreeViewColumn *column = list->data;
2501           const gchar *detail = NULL;
2502
2503           if (!column->visible)
2504             continue;
2505
2506           if (cell_offset > event->area.x + event->area.width ||
2507               cell_offset + column->displayed_width < event->area.x)
2508             {
2509               cell_offset += column->displayed_width;
2510               continue;
2511             }
2512
2513           if (column->show_sort_indicator)
2514             flags |= GTK_CELL_RENDERER_SORTED;
2515           else
2516             flags &= ~GTK_CELL_RENDERER_SORTED;
2517
2518           gtk_tree_view_column_cell_set_cell_data (column,
2519                                                    tree_view->priv->model,
2520                                                    &iter);
2521
2522           background_area.x = cell_offset;
2523           background_area.width = column->displayed_width;
2524
2525           cell_area = background_area;
2526           cell_area.y += vertical_separator / 2;
2527           cell_area.height -= vertical_separator;
2528
2529           /* Select the detail for drawing the cell.  relevant
2530            * factors are parity, sortedness, and whether to
2531            * display rules.
2532            */
2533
2534           /* FIXME when we have style properties, clean this up.
2535            */
2536
2537           if (tree_view->priv->has_rules)
2538             {
2539               if (flags & GTK_CELL_RENDERER_SORTED)
2540                 {
2541                   if (parity)
2542                     detail = "cell_odd_ruled_sorted";
2543                   else
2544                     detail = "cell_even_ruled_sorted";
2545                 }
2546               else
2547                 {
2548                   if (parity)
2549                     detail = "cell_odd_ruled";
2550                   else
2551                     detail = "cell_even_ruled";
2552                 }
2553             }
2554           else
2555             {
2556               if (flags & GTK_CELL_RENDERER_SORTED)
2557                 {
2558                   if (parity)
2559                     detail = "cell_odd_sorted";
2560                   else
2561                     detail = "cell_even_sorted";
2562                 }
2563               else
2564                 {
2565                   if (parity)
2566                     detail = "cell_odd";
2567                   else
2568                     detail = "cell_even";
2569                 }
2570             }
2571
2572           g_assert (detail);
2573
2574           /* Draw background */
2575           gtk_paint_flat_box (widget->style,
2576                               event->window,
2577                               (flags & GTK_CELL_RENDERER_SELECTED) ?
2578                               GTK_STATE_SELECTED : GTK_STATE_NORMAL,
2579                               GTK_SHADOW_NONE,
2580                               &event->area,
2581                               widget,
2582                               detail,
2583                               background_area.x,
2584                               background_area.y,
2585                               background_area.width,
2586                               background_area.height);
2587
2588           if (gtk_tree_view_is_expander_column (tree_view, column) &&
2589               TREE_VIEW_DRAW_EXPANDERS(tree_view))
2590             {
2591               cell_area.x += depth*tree_view->priv->tab_offset;
2592               cell_area.width -= depth*tree_view->priv->tab_offset;
2593
2594               /* If we have an expander column, the highlight underline
2595                * starts with that column, so that it indicates which
2596                * level of the tree we're dropping at.
2597                */
2598               highlight_x = cell_area.x;
2599
2600               gtk_tree_view_column_cell_render (column,
2601                                                 event->window,
2602                                                 &background_area,
2603                                                 &cell_area,
2604                                                 &event->area,
2605                                                 flags);
2606               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
2607                 {
2608                   gint x, y;
2609                   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
2610                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2611                                             tree,
2612                                             node,
2613                                             x, y);
2614                 }
2615             }
2616           else
2617             {
2618               gtk_tree_view_column_cell_render (column,
2619                                                 event->window,
2620                                                 &background_area,
2621                                                 &cell_area,
2622                                                 &event->area,
2623                                                 flags);
2624             }
2625           cell_offset += column->displayed_width;
2626         }
2627
2628       if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
2629         gtk_tree_view_draw_focus (widget);
2630
2631       if (node == drag_highlight)
2632         {
2633           /* Draw indicator for the drop
2634            */
2635           gint highlight_y = -1;
2636           GtkRBTree *tree = NULL;
2637           GtkRBNode *node = NULL;
2638           gint width;
2639
2640           switch (tree_view->priv->drag_dest_pos)
2641             {
2642             case GTK_TREE_VIEW_DROP_BEFORE:
2643               highlight_y = background_area.y - vertical_separator/2;
2644               break;
2645
2646             case GTK_TREE_VIEW_DROP_AFTER:
2647               highlight_y = background_area.y + background_area.height + vertical_separator/2;
2648               break;
2649
2650             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2651             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2652               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
2653
2654               if (tree == NULL)
2655                 break;
2656               gdk_drawable_get_size (tree_view->priv->bin_window,
2657                                      &width, NULL);
2658               gtk_paint_focus (widget->style,
2659                                tree_view->priv->bin_window,
2660                                NULL,
2661                                widget,
2662                                "add-mode",
2663                                0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
2664                                width - 1, BACKGROUND_HEIGHT (node) - 1);
2665
2666               break;
2667             }
2668
2669           if (highlight_y >= 0)
2670             {
2671               gdk_draw_line (event->window,
2672                              widget->style->black_gc,
2673                              highlight_x,
2674                              highlight_y,
2675                              bin_window_width - highlight_x,
2676                              highlight_y);
2677             }
2678         }
2679
2680       y_offset += max_height;
2681       if (node->children)
2682         {
2683           GtkTreeIter parent = iter;
2684           gboolean has_child;
2685
2686           tree = node->children;
2687           node = tree->root;
2688
2689           g_assert (node != tree->nil);
2690
2691           while (node->left != tree->nil)
2692             node = node->left;
2693           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
2694                                                     &iter,
2695                                                     &parent);
2696           depth++;
2697
2698           /* Sanity Check! */
2699           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
2700         }
2701       else
2702         {
2703           gboolean done = FALSE;
2704           do
2705             {
2706               node = _gtk_rbtree_next (tree, node);
2707               if (node != NULL)
2708                 {
2709                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
2710                   done = TRUE;
2711
2712                   /* Sanity Check! */
2713                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
2714                 }
2715               else
2716                 {
2717                   GtkTreeIter parent_iter = iter;
2718                   gboolean has_parent;
2719
2720                   node = tree->parent_node;
2721                   tree = tree->parent_tree;
2722                   if (tree == NULL)
2723                     /* we've run out of tree.  It's okay to return though, as
2724                      * we'd only break out of the while loop below. */
2725                     return TRUE;
2726                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
2727                                                            &iter,
2728                                                            &parent_iter);
2729                   depth--;
2730
2731                   /* Sanity check */
2732                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
2733                 }
2734             }
2735           while (!done);
2736         }
2737     }
2738   while (y_offset < event->area.height);
2739
2740   if (cursor_path)
2741     gtk_tree_path_free (cursor_path);
2742
2743   if (drag_dest_path)
2744     gtk_tree_path_free (drag_dest_path);
2745
2746   return TRUE;
2747 }
2748
2749 static gboolean
2750 gtk_tree_view_expose (GtkWidget      *widget,
2751                       GdkEventExpose *event)
2752 {
2753   GtkTreeView *tree_view;
2754
2755   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2756
2757   tree_view = GTK_TREE_VIEW (widget);
2758
2759   if (event->window == tree_view->priv->bin_window)
2760     return gtk_tree_view_bin_expose (widget, event);
2761
2762   return TRUE;
2763 }
2764
2765 static gboolean
2766 gtk_tree_view_key_press (GtkWidget   *widget,
2767                          GdkEventKey *event)
2768 {
2769   GtkTreeView *tree_view = (GtkTreeView *) widget;
2770
2771   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2772     {
2773       if (event->keyval == GDK_Escape)
2774         {
2775           tree_view->priv->cur_reorder = NULL;
2776           gtk_tree_view_button_release_drag_column (widget, NULL);
2777         }
2778       return TRUE;
2779     }
2780   return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
2781 }
2782
2783 /* FIXME Is this function necessary? Can I get an enter_notify event
2784  * w/o either an expose event or a mouse motion event?
2785  */
2786 static gboolean
2787 gtk_tree_view_enter_notify (GtkWidget        *widget,
2788                             GdkEventCrossing *event)
2789 {
2790   GtkTreeView *tree_view;
2791   GtkRBTree *tree;
2792   GtkRBNode *node;
2793   gint new_y;
2794
2795   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2796
2797   tree_view = GTK_TREE_VIEW (widget);
2798
2799   /* Sanity check it */
2800   if (event->window != tree_view->priv->bin_window)
2801     return FALSE;
2802
2803   if (tree_view->priv->tree == NULL)
2804     return FALSE;
2805
2806   if ((tree_view->priv->button_pressed_node != NULL) &&
2807       (tree_view->priv->button_pressed_node != node))
2808     return TRUE;
2809
2810   /* find the node internally */
2811   new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
2812
2813   _gtk_rbtree_find_offset (tree_view->priv->tree,
2814                            TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
2815                            &tree,
2816                            &node);
2817
2818   if (node == NULL)
2819     return FALSE;
2820
2821   do_prelight (tree_view, tree, node, event->x, new_y);
2822
2823   if (tree_view->priv->prelight_node)
2824     gtk_tree_view_queue_draw_node (tree_view,
2825                                    tree_view->priv->prelight_tree,
2826                                    tree_view->priv->prelight_node,
2827                                    NULL);
2828
2829   return TRUE;
2830 }
2831
2832 static gboolean
2833 gtk_tree_view_leave_notify (GtkWidget        *widget,
2834                             GdkEventCrossing *event)
2835 {
2836   GtkTreeView *tree_view;
2837
2838   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2839
2840   tree_view = GTK_TREE_VIEW (widget);
2841
2842   if (tree_view->priv->prelight_node)
2843     gtk_tree_view_queue_draw_node (tree_view,
2844                                    tree_view->priv->prelight_tree,
2845                                    tree_view->priv->prelight_node,
2846                                    NULL);
2847
2848   ensure_unprelighted (tree_view);
2849
2850   return TRUE;
2851 }
2852
2853
2854 static gint
2855 gtk_tree_view_focus_in (GtkWidget     *widget,
2856                         GdkEventFocus *event)
2857 {
2858   GtkTreeView *tree_view;
2859
2860   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2861   g_return_val_if_fail (event != NULL, FALSE);
2862
2863   tree_view = GTK_TREE_VIEW (widget);
2864
2865   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2866
2867   gtk_widget_queue_draw (widget);
2868
2869   return FALSE;
2870 }
2871
2872
2873 static gint
2874 gtk_tree_view_focus_out (GtkWidget     *widget,
2875                          GdkEventFocus *event)
2876 {
2877   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2878   g_return_val_if_fail (event != NULL, FALSE);
2879
2880   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2881
2882   gtk_widget_queue_draw (widget);
2883   GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE;
2884   GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE;
2885   return FALSE;
2886 }
2887
2888
2889 /* Drag-and-drop */
2890
2891 static void
2892 set_source_row (GdkDragContext *context,
2893                 GtkTreeModel   *model,
2894                 GtkTreePath    *source_row)
2895 {
2896   g_object_set_data_full (G_OBJECT (context),
2897                           "gtk-tree-view-source-row",
2898                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
2899                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
2900 }
2901
2902 static GtkTreePath*
2903 get_source_row (GdkDragContext *context)
2904 {
2905   GtkTreeRowReference *ref =
2906     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
2907
2908   if (ref)
2909     return gtk_tree_row_reference_get_path (ref);
2910   else
2911     return NULL;
2912 }
2913
2914
2915 static void
2916 set_dest_row (GdkDragContext *context,
2917               GtkTreeModel   *model,
2918               GtkTreePath    *dest_row)
2919 {
2920   g_object_set_data_full (G_OBJECT (context),
2921                           "gtk-tree-view-dest-row",
2922                           dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
2923                           (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
2924 }
2925
2926 static GtkTreePath*
2927 get_dest_row (GdkDragContext *context)
2928 {
2929   GtkTreeRowReference *ref =
2930     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
2931
2932   if (ref)
2933     return gtk_tree_row_reference_get_path (ref);
2934   else
2935     return NULL;
2936 }
2937
2938 /* Get/set whether drag_motion requested the drag data and
2939  * drag_data_received should thus not actually insert the data,
2940  * since the data doesn't result from a drop.
2941  */
2942 static void
2943 set_status_pending (GdkDragContext *context,
2944                     GdkDragAction   suggested_action)
2945 {
2946   g_object_set_data (G_OBJECT (context),
2947                      "gtk-tree-view-status-pending",
2948                      GINT_TO_POINTER (suggested_action));
2949 }
2950
2951 static GdkDragAction
2952 get_status_pending (GdkDragContext *context)
2953 {
2954   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
2955                                              "gtk-tree-view-status-pending"));
2956 }
2957
2958 static TreeViewDragInfo*
2959 get_info (GtkTreeView *tree_view)
2960 {
2961   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
2962 }
2963
2964 static void
2965 clear_source_info (TreeViewDragInfo *di)
2966 {
2967   if (di->source_target_list)
2968     gtk_target_list_unref (di->source_target_list);
2969
2970   if (di->row_draggable_closure)
2971     g_closure_unref (di->row_draggable_closure);
2972
2973   di->source_target_list = NULL;
2974   di->row_draggable_closure = NULL;
2975 }
2976
2977 static void
2978 clear_dest_info (TreeViewDragInfo *di)
2979 {
2980   if (di->location_droppable_closure)
2981     g_closure_unref (di->location_droppable_closure);
2982
2983   if (di->dest_target_list)
2984     gtk_target_list_unref (di->dest_target_list);
2985
2986   di->location_droppable_closure = NULL;
2987   di->dest_target_list = NULL;
2988 }
2989
2990 static void
2991 destroy_info (TreeViewDragInfo *di)
2992 {
2993   clear_source_info (di);
2994   clear_dest_info (di);
2995   g_free (di);
2996 }
2997
2998 static TreeViewDragInfo*
2999 ensure_info (GtkTreeView *tree_view)
3000 {
3001   TreeViewDragInfo *di;
3002
3003   di = get_info (tree_view);
3004
3005   if (di == NULL)
3006     {
3007       di = g_new0 (TreeViewDragInfo, 1);
3008
3009       g_object_set_data_full (G_OBJECT (tree_view),
3010                               "gtk-tree-view-drag-info",
3011                               di,
3012                               (GDestroyNotify) destroy_info);
3013     }
3014
3015   return di;
3016 }
3017
3018 static void
3019 remove_info (GtkTreeView *tree_view)
3020 {
3021   g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
3022 }
3023
3024 static gint
3025 drag_scan_timeout (gpointer data)
3026 {
3027   GtkTreeView *tree_view;
3028   gint x, y;
3029   GdkModifierType state;
3030   GtkTreePath *path = NULL;
3031   GtkTreeViewColumn *column = NULL;
3032   GdkRectangle visible_rect;
3033
3034   tree_view = GTK_TREE_VIEW (data);
3035
3036   gdk_window_get_pointer (tree_view->priv->bin_window,
3037                           &x, &y, &state);
3038
3039   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3040
3041   /* See if we are near the edge. */
3042   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
3043       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
3044       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
3045       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
3046     {
3047       gtk_tree_view_get_path_at_pos (tree_view,
3048                                      tree_view->priv->bin_window,
3049                                      x, y,
3050                                      &path,
3051                                      &column,
3052                                      NULL,
3053                                      NULL);
3054
3055       if (path != NULL)
3056         {
3057           gtk_tree_view_scroll_to_cell (tree_view,
3058                                         path,
3059                                         column,
3060                                         0.5, 0.5);
3061
3062           gtk_tree_path_free (path);
3063         }
3064     }
3065
3066   return TRUE;
3067 }
3068
3069
3070 static void
3071 remove_scroll_timeout (GtkTreeView *tree_view)
3072 {
3073   if (tree_view->priv->scroll_timeout != 0)
3074     {
3075       gtk_timeout_remove (tree_view->priv->scroll_timeout);
3076       tree_view->priv->scroll_timeout = 0;
3077     }
3078 }
3079 static gboolean
3080 check_model_dnd (GtkTreeModel *model,
3081                  GType         required_iface,
3082                  const gchar  *signal)
3083 {
3084   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
3085     {
3086       g_warning ("You must override the default '%s' handler "
3087                  "on GtkTreeView when using models that don't support "
3088                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
3089                  "is to connect to '%s' and call "
3090                  "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
3091                  "the default handler from running. Look at the source code "
3092                  "for the default handler in gtktreeview.c to get an idea what "
3093                  "your handler should do. (gtktreeview.c is in the GTK source "
3094                  "code.) If you're using GTK from a language other than C, "
3095                  "there may be a more natural way to override default handlers, e.g. via derivation.",
3096                  signal, g_type_name (required_iface), signal);
3097       return FALSE;
3098     }
3099   else
3100     return TRUE;
3101 }
3102
3103 static void
3104 remove_open_timeout (GtkTreeView *tree_view)
3105 {
3106   if (tree_view->priv->open_dest_timeout != 0)
3107     {
3108       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
3109       tree_view->priv->open_dest_timeout = 0;
3110     }
3111 }
3112
3113
3114 static gint
3115 open_row_timeout (gpointer data)
3116 {
3117   GtkTreeView *tree_view = data;
3118   GtkTreePath *dest_path = NULL;
3119   GtkTreeViewDropPosition pos;
3120
3121   gtk_tree_view_get_drag_dest_row (tree_view,
3122                                    &dest_path,
3123                                    &pos);
3124
3125   if (dest_path &&
3126       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3127        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3128     {
3129       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
3130       tree_view->priv->open_dest_timeout = 0;
3131
3132       gtk_tree_path_free (dest_path);
3133
3134       return FALSE;
3135     }
3136   else
3137     {
3138       if (dest_path)
3139         gtk_tree_path_free (dest_path);
3140       return TRUE;
3141     }
3142 }
3143
3144 /* Returns TRUE if event should not be propagated to parent widgets */
3145 static gboolean
3146 set_destination_row (GtkTreeView    *tree_view,
3147                      GdkDragContext *context,
3148                      gint            x,
3149                      gint            y,
3150                      GdkDragAction  *suggested_action,
3151                      GdkAtom        *target)
3152 {
3153   GtkTreePath *path = NULL;
3154   GtkTreeViewDropPosition pos;
3155   GtkTreeViewDropPosition old_pos;
3156   TreeViewDragInfo *di;
3157   GtkWidget *widget;
3158   GtkTreePath *old_dest_path = NULL;
3159
3160   *suggested_action = 0;
3161   *target = GDK_NONE;
3162
3163   widget = GTK_WIDGET (tree_view);
3164
3165   di = get_info (tree_view);
3166
3167   if (di == NULL)
3168     {
3169       /* someone unset us as a drag dest, note that if
3170        * we return FALSE drag_leave isn't called
3171        */
3172
3173       gtk_tree_view_set_drag_dest_row (tree_view,
3174                                        NULL,
3175                                        GTK_TREE_VIEW_DROP_BEFORE);
3176
3177       remove_scroll_timeout (GTK_TREE_VIEW (widget));
3178       remove_open_timeout (GTK_TREE_VIEW (widget));
3179
3180       return FALSE; /* no longer a drop site */
3181     }
3182
3183   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
3184   if (*target == GDK_NONE)
3185     {
3186       return FALSE;
3187     }
3188
3189   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
3190                                           x, y,
3191                                           &path,
3192                                           &pos))
3193     {
3194       /* can't drop here */
3195       remove_open_timeout (tree_view);
3196
3197       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3198                                        NULL,
3199                                        GTK_TREE_VIEW_DROP_BEFORE);
3200
3201       /* don't propagate to parent though */
3202       return TRUE;
3203     }
3204
3205   g_assert (path);
3206
3207   /* If we left the current row's "open" zone, unset the timeout for
3208    * opening the row
3209    */
3210   gtk_tree_view_get_drag_dest_row (tree_view,
3211                                    &old_dest_path,
3212                                    &old_pos);
3213
3214   if (old_dest_path &&
3215       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
3216        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3217          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
3218     remove_open_timeout (tree_view);
3219
3220   if (old_dest_path)
3221     gtk_tree_path_free (old_dest_path);
3222
3223   if (TRUE /* FIXME if the location droppable predicate */)
3224     {
3225       GtkWidget *source_widget;
3226
3227       *suggested_action = context->suggested_action;
3228
3229       source_widget = gtk_drag_get_source_widget (context);
3230
3231       if (source_widget == widget)
3232         {
3233           /* Default to MOVE, unless the user has
3234            * pressed ctrl or alt to affect available actions
3235            */
3236           if ((context->actions & GDK_ACTION_MOVE) != 0)
3237             *suggested_action = GDK_ACTION_MOVE;
3238         }
3239
3240       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3241                                        path, pos);
3242     }
3243   else
3244     {
3245       /* can't drop here */
3246       remove_open_timeout (tree_view);
3247
3248       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3249                                        NULL,
3250                                        GTK_TREE_VIEW_DROP_BEFORE);
3251     }
3252
3253   return TRUE;
3254 }
3255 static GtkTreePath*
3256 get_logical_dest_row (GtkTreeView *tree_view)
3257
3258 {
3259   /* adjust path to point to the row the drop goes in front of */
3260   GtkTreePath *path = NULL;
3261   GtkTreeViewDropPosition pos;
3262
3263   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3264
3265   if (path == NULL)
3266     return NULL;
3267
3268   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
3269     ; /* do nothing */
3270   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
3271            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3272     {
3273       /* get first child, drop before it */
3274       gtk_tree_path_append_index (path, 0);
3275     }
3276   else
3277     {
3278       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
3279       gtk_tree_path_next (path);
3280     }
3281
3282   return path;
3283 }
3284
3285 static gboolean
3286 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
3287                                         GdkEventMotion   *event)
3288 {
3289   GdkDragContext *context;
3290   TreeViewDragInfo *di;
3291   GtkTreePath *path = NULL;
3292   gint button;
3293   gint cell_x, cell_y;
3294   GtkTreeModel *model;
3295
3296   di = get_info (tree_view);
3297
3298   if (di == NULL)
3299     return FALSE;
3300
3301   if (tree_view->priv->pressed_button < 0)
3302     return FALSE;
3303
3304   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
3305                                  tree_view->priv->press_start_x,
3306                                  tree_view->priv->press_start_y,
3307                                  event->x, event->y))
3308     return FALSE;
3309
3310   model = gtk_tree_view_get_model (tree_view);
3311
3312   if (model == NULL)
3313     return FALSE;
3314
3315   button = tree_view->priv->pressed_button;
3316   tree_view->priv->pressed_button = -1;
3317
3318   gtk_tree_view_get_path_at_pos (tree_view,
3319                                  tree_view->priv->bin_window,
3320                                  tree_view->priv->press_start_x,
3321                                  tree_view->priv->press_start_y,
3322                                  &path,
3323                                  NULL,
3324                                  &cell_x,
3325                                  &cell_y);
3326
3327   if (path == NULL)
3328     return FALSE;
3329
3330   /* FIXME if the path doesn't match the row_draggable predicate,
3331    * return FALSE and free path
3332    */
3333
3334   /* FIXME Check whether we're a start button, if not return FALSE and
3335    * free path
3336    */
3337
3338   context = gtk_drag_begin (GTK_WIDGET (tree_view),
3339                             di->source_target_list,
3340                             di->source_actions,
3341                             button,
3342                             (GdkEvent*)event);
3343
3344   gtk_drag_set_icon_default (context);
3345
3346   {
3347     GdkPixmap *row_pix;
3348
3349     row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
3350                                                   path);
3351
3352     gtk_drag_set_icon_pixmap (context,
3353                               gdk_drawable_get_colormap (row_pix),
3354                               row_pix,
3355                               NULL,
3356                               /* the + 1 is for the black border in the icon */
3357                               tree_view->priv->press_start_x + 1,
3358                               cell_y + 1);
3359
3360     gdk_pixmap_unref (row_pix);
3361   }
3362
3363   set_source_row (context, model, path);
3364   gtk_tree_path_free (path);
3365
3366   return TRUE;
3367 }
3368
3369
3370 static void
3371 gtk_tree_view_drag_begin (GtkWidget      *widget,
3372                           GdkDragContext *context)
3373 {
3374   /* do nothing */
3375 }
3376
3377 static void
3378 gtk_tree_view_drag_end (GtkWidget      *widget,
3379                         GdkDragContext *context)
3380 {
3381   /* do nothing */
3382 }
3383
3384 /* Default signal implementations for the drag signals */
3385 static void
3386 gtk_tree_view_drag_data_get (GtkWidget        *widget,
3387                              GdkDragContext   *context,
3388                              GtkSelectionData *selection_data,
3389                              guint             info,
3390                              guint             time)
3391 {
3392   GtkTreeView *tree_view;
3393   GtkTreeModel *model;
3394   TreeViewDragInfo *di;
3395   GtkTreePath *source_row;
3396
3397   tree_view = GTK_TREE_VIEW (widget);
3398
3399   model = gtk_tree_view_get_model (tree_view);
3400
3401   if (model == NULL)
3402     return;
3403
3404   di = get_info (GTK_TREE_VIEW (widget));
3405
3406   if (di == NULL)
3407     return;
3408
3409   source_row = get_source_row (context);
3410
3411   if (source_row == NULL)
3412     return;
3413
3414   /* We can implement the GTK_TREE_MODEL_ROW target generically for
3415    * any model; for DragSource models there are some other targets
3416    * we also support.
3417    */
3418
3419   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
3420       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
3421                                           source_row,
3422                                           selection_data))
3423     goto done;
3424
3425   /* If drag_data_get does nothing, try providing row data. */
3426   if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3427     {
3428       gtk_selection_data_set_tree_row (selection_data,
3429                                        model,
3430                                        source_row);
3431     }
3432
3433  done:
3434   gtk_tree_path_free (source_row);
3435 }
3436
3437
3438 static void
3439 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
3440                                 GdkDragContext *context)
3441 {
3442   TreeViewDragInfo *di;
3443   GtkTreeModel *model;
3444   GtkTreeView *tree_view;
3445   GtkTreePath *source_row;
3446
3447   tree_view = GTK_TREE_VIEW (widget);
3448   model = gtk_tree_view_get_model (tree_view);
3449
3450   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
3451     return;
3452
3453   di = get_info (tree_view);
3454
3455   if (di == NULL)
3456     return;
3457
3458   source_row = get_source_row (context);
3459
3460   if (source_row == NULL)
3461     return;
3462
3463   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
3464                                          source_row);
3465
3466   gtk_tree_path_free (source_row);
3467
3468   set_source_row (context, NULL, NULL);
3469 }
3470
3471 static void
3472 gtk_tree_view_drag_leave (GtkWidget      *widget,
3473                           GdkDragContext *context,
3474                           guint             time)
3475 {
3476   TreeViewDragInfo *di;
3477
3478   di = get_info (GTK_TREE_VIEW (widget));
3479
3480   /* unset any highlight row */
3481   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3482                                    NULL,
3483                                    GTK_TREE_VIEW_DROP_BEFORE);
3484
3485   remove_scroll_timeout (GTK_TREE_VIEW (widget));
3486   remove_open_timeout (GTK_TREE_VIEW (widget));
3487 }
3488
3489
3490 static gboolean
3491 gtk_tree_view_drag_motion (GtkWidget        *widget,
3492                            GdkDragContext   *context,
3493                            gint              x,
3494                            gint              y,
3495                            guint             time)
3496 {
3497   GtkTreePath *path = NULL;
3498   GtkTreeViewDropPosition pos;
3499   GtkTreeView *tree_view;
3500   GdkDragAction suggested_action = 0;
3501   GdkAtom target;
3502
3503   tree_view = GTK_TREE_VIEW (widget);
3504
3505   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3506     return FALSE;
3507
3508   //  gtk_tree_view_ensure_scroll_timeout (tree_view);
3509
3510   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
3511
3512   if (path == NULL)
3513     {
3514       /* Can't drop here. */
3515       gdk_drag_status (context, 0, time);
3516     }
3517   else
3518     {
3519       if (tree_view->priv->open_dest_timeout == 0 &&
3520           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3521            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
3522         {
3523           tree_view->priv->open_dest_timeout =
3524             gtk_timeout_add (500, open_row_timeout, tree_view);
3525         }
3526
3527       if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
3528         {
3529           /* Request data so we can use the source row when
3530            * determining whether to accept the drop
3531            */
3532           set_status_pending (context, suggested_action);
3533           gtk_drag_get_data (widget, context, target, time);
3534         }
3535       else
3536         {
3537           set_status_pending (context, 0);
3538           gdk_drag_status (context, suggested_action, time);
3539         }
3540     }
3541
3542   if (path)
3543     gtk_tree_path_free (path);
3544
3545   return TRUE;
3546 }
3547
3548
3549 static gboolean
3550 gtk_tree_view_drag_drop (GtkWidget        *widget,
3551                          GdkDragContext   *context,
3552                          gint              x,
3553                          gint              y,
3554                          guint             time)
3555 {
3556   GtkTreeView *tree_view;
3557   GtkTreePath *path;
3558   GdkDragAction suggested_action = 0;
3559   GdkAtom target = GDK_NONE;
3560   TreeViewDragInfo *di;
3561   GtkTreeModel *model;
3562
3563   tree_view = GTK_TREE_VIEW (widget);
3564
3565   model = gtk_tree_view_get_model (tree_view);
3566
3567   remove_scroll_timeout (GTK_TREE_VIEW (widget));
3568   remove_open_timeout (GTK_TREE_VIEW (widget));
3569
3570   di = get_info (tree_view);
3571
3572   if (di == NULL)
3573     return FALSE;
3574
3575   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
3576     return FALSE;
3577
3578   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
3579     return FALSE;
3580
3581   path = get_logical_dest_row (tree_view);
3582
3583   if (target != GDK_NONE && path != NULL)
3584     {
3585       /* in case a motion had requested drag data, change things so we
3586        * treat drag data receives as a drop.
3587        */
3588       set_status_pending (context, 0);
3589
3590       set_dest_row (context, model, path);
3591     }
3592
3593   if (path)
3594     gtk_tree_path_free (path);
3595
3596   /* Unset this thing */
3597   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3598                                    NULL,
3599                                    GTK_TREE_VIEW_DROP_BEFORE);
3600
3601   if (target != GDK_NONE)
3602     {
3603       gtk_drag_get_data (widget, context, target, time);
3604       return TRUE;
3605     }
3606   else
3607     return FALSE;
3608 }
3609
3610 static void
3611 gtk_tree_view_drag_data_received (GtkWidget        *widget,
3612                                   GdkDragContext   *context,
3613                                   gint              x,
3614                                   gint              y,
3615                                   GtkSelectionData *selection_data,
3616                                   guint             info,
3617                                   guint             time)
3618 {
3619   GtkTreePath *path;
3620   TreeViewDragInfo *di;
3621   gboolean accepted = FALSE;
3622   GtkTreeModel *model;
3623   GtkTreeView *tree_view;
3624   GtkTreePath *dest_row;
3625   GdkDragAction suggested_action;
3626
3627   tree_view = GTK_TREE_VIEW (widget);
3628
3629   model = gtk_tree_view_get_model (tree_view);
3630
3631   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
3632     return;
3633
3634   di = get_info (tree_view);
3635
3636   if (di == NULL)
3637     return;
3638
3639   suggested_action = get_status_pending (context);
3640
3641   if (suggested_action)
3642     {
3643       /* We are getting this data due to a request in drag_motion,
3644        * rather than due to a request in drag_drop, so we are just
3645        * supposed to call drag_status, not actually paste in the
3646        * data.
3647        */
3648       path = get_logical_dest_row (tree_view);
3649
3650       if (path == NULL)
3651         suggested_action = 0;
3652
3653       if (suggested_action)
3654         {
3655           GtkTreeModel *src_model = NULL;
3656           GtkTreePath *src_path = NULL;
3657
3658           if (!gtk_selection_data_get_tree_row (selection_data,
3659                                                 &src_model,
3660                                                 &src_path))
3661             suggested_action = 0;
3662
3663           if (suggested_action)
3664             {
3665               if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
3666                                                          src_model,
3667                                                          src_path,
3668                                                          path))
3669                 suggested_action = 0;
3670
3671               gtk_tree_path_free (src_path);
3672             }
3673         }
3674
3675       gdk_drag_status (context, suggested_action, time);
3676
3677       if (path)
3678         gtk_tree_path_free (path);
3679
3680       /* If you can't drop, remove user drop indicator until the next motion */
3681       if (suggested_action == 0)
3682         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
3683                                          NULL,
3684                                          GTK_TREE_VIEW_DROP_BEFORE);
3685
3686       return;
3687     }
3688
3689   dest_row = get_dest_row (context);
3690
3691   if (dest_row == NULL)
3692     return;
3693
3694   if (selection_data->length >= 0)
3695     {
3696       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
3697                                                  dest_row,
3698                                                  selection_data))
3699         accepted = TRUE;
3700     }
3701
3702   gtk_drag_finish (context,
3703                    accepted,
3704                    (context->action == GDK_ACTION_MOVE),
3705                    time);
3706
3707   gtk_tree_path_free (dest_row);
3708
3709   /* drop dest_row */
3710   set_dest_row (context, NULL, NULL);
3711 }
3712
3713
3714
3715 /* GtkContainer Methods
3716  */
3717
3718
3719 static void
3720 gtk_tree_view_remove (GtkContainer *container,
3721                       GtkWidget    *widget)
3722 {
3723   GtkTreeView *tree_view;
3724   GtkTreeViewChild *child = NULL;
3725   GList *tmp_list;
3726
3727   g_return_if_fail (GTK_IS_TREE_VIEW (container));
3728
3729   tree_view = GTK_TREE_VIEW (container);
3730
3731   tmp_list = tree_view->priv->children;
3732   while (tmp_list)
3733     {
3734       child = tmp_list->data;
3735       if (child->widget == widget)
3736         {
3737           gtk_widget_unparent (widget);
3738
3739           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
3740           g_list_free_1 (tmp_list);
3741           g_free (child);
3742           return;
3743         }
3744
3745       tmp_list = tmp_list->next;
3746     }
3747
3748   tmp_list = tree_view->priv->columns;
3749
3750   while (tmp_list)
3751     {
3752       GtkTreeViewColumn *column;
3753       column = tmp_list->data;
3754       if (column->button == widget)
3755         {
3756           gtk_widget_unparent (widget);
3757           return;
3758         }
3759       tmp_list = tmp_list->next;
3760     }
3761
3762 }
3763
3764 static void
3765 gtk_tree_view_forall (GtkContainer *container,
3766                       gboolean      include_internals,
3767                       GtkCallback   callback,
3768                       gpointer      callback_data)
3769 {
3770   GtkTreeView *tree_view;
3771   GtkTreeViewChild *child = NULL;
3772   GtkTreeViewColumn *column;
3773   GList *tmp_list;
3774
3775   g_return_if_fail (GTK_IS_TREE_VIEW (container));
3776   g_return_if_fail (callback != NULL);
3777
3778   tree_view = GTK_TREE_VIEW (container);
3779
3780   tmp_list = tree_view->priv->children;
3781   while (tmp_list)
3782     {
3783       child = tmp_list->data;
3784       tmp_list = tmp_list->next;
3785
3786       (* callback) (child->widget, callback_data);
3787     }
3788   if (include_internals == FALSE)
3789     return;
3790
3791   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3792     {
3793       column = tmp_list->data;
3794
3795       if (column->button)
3796         (* callback) (column->button, callback_data);
3797     }
3798 }
3799
3800 /* Returns TRUE if the focus is within the headers, after the focus operation is
3801  * done
3802  */
3803 static gboolean
3804 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
3805                             GtkDirectionType  dir)
3806 {
3807   GtkWidget *focus_child;
3808   GtkContainer *container;
3809
3810   GList *last_column, *first_column;
3811   GList *tmp_list;
3812
3813   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
3814     return FALSE;
3815
3816   focus_child = GTK_CONTAINER (tree_view)->focus_child;
3817   container = GTK_CONTAINER (tree_view);
3818
3819   last_column = g_list_last (tree_view->priv->columns);
3820   while (last_column)
3821     {
3822       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
3823           GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
3824         break;
3825       last_column = last_column->prev;
3826     }
3827
3828   /* No headers are visible, or are focusable.  We can't focus in or out.
3829    */
3830   if (last_column == NULL)
3831     return FALSE;
3832
3833   first_column = tree_view->priv->columns;
3834   while (first_column)
3835     {
3836       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
3837           GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
3838         break;
3839       first_column = first_column->next;
3840     }
3841
3842   switch (dir)
3843     {
3844     case GTK_DIR_TAB_BACKWARD:
3845     case GTK_DIR_TAB_FORWARD:
3846     case GTK_DIR_UP:
3847     case GTK_DIR_DOWN:
3848       if (focus_child == NULL)
3849         {
3850           if (tree_view->priv->focus_column != NULL)
3851             focus_child = tree_view->priv->focus_column->button;
3852           else
3853             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3854           gtk_widget_grab_focus (focus_child);
3855           break;
3856         }
3857       return FALSE;
3858
3859     case GTK_DIR_LEFT:
3860     case GTK_DIR_RIGHT:
3861       if (focus_child == NULL)
3862         {
3863           if (tree_view->priv->focus_column != NULL)
3864             focus_child = tree_view->priv->focus_column->button;
3865           else if (dir == GTK_DIR_LEFT)
3866             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3867           else
3868             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3869           gtk_widget_grab_focus (focus_child);
3870           break;
3871         }
3872
3873       if (gtk_widget_child_focus (focus_child, dir))
3874         {
3875           /* The focus moves inside the button. */
3876           /* This is probably a great example of bad UI */
3877           break;
3878         }
3879
3880       /* We need to move the focus among the row of buttons. */
3881       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3882         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3883           break;
3884
3885       if (tmp_list == first_column && dir == GTK_DIR_LEFT)
3886         {
3887           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
3888           gtk_widget_grab_focus (focus_child);
3889           break;
3890         }
3891       else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
3892         {
3893           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
3894           gtk_widget_grab_focus (focus_child);
3895           break;
3896         }
3897
3898       while (tmp_list)
3899         {
3900           GtkTreeViewColumn *column;
3901
3902           if (dir == GTK_DIR_RIGHT)
3903             tmp_list = tmp_list->next;
3904           else
3905             tmp_list = tmp_list->prev;
3906
3907           if (tmp_list == NULL)
3908             {
3909               g_warning ("Internal button not found");
3910               break;
3911             }
3912           column = tmp_list->data;
3913           if (column->button &&
3914               column->visible &&
3915               GTK_WIDGET_CAN_FOCUS (column->button))
3916             {
3917               focus_child = column->button;
3918               gtk_widget_grab_focus (column->button);
3919               break;
3920             }
3921         }
3922       break;
3923     default:
3924       g_assert_not_reached ();
3925       break;
3926     }
3927
3928   /* if focus child is non-null, we assume it's been set to the current focus child
3929    */
3930   if (focus_child)
3931     {
3932       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
3933         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
3934           break;
3935
3936       tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3937
3938       /* If the following isn't true, then the view is smaller then the scrollpane.
3939        */
3940       if ((focus_child->allocation.x + focus_child->allocation.width) <=
3941           (tree_view->priv->hadjustment->upper))
3942         {
3943           /* Scroll to the button, if needed */
3944           if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
3945               (focus_child->allocation.x + focus_child->allocation.width))
3946             gtk_adjustment_set_value (tree_view->priv->hadjustment,
3947                                       focus_child->allocation.x + focus_child->allocation.width -
3948                                       tree_view->priv->hadjustment->page_size);
3949           else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
3950             gtk_adjustment_set_value (tree_view->priv->hadjustment,
3951                                       focus_child->allocation.x);
3952         }
3953     }
3954
3955   return (focus_child != NULL);
3956 }
3957
3958 /* We make the assumption that if container->focus_child != NULL, the focus must
3959  * be in the header.  For now, this is accurate.  It may not be in the future.
3960  */
3961
3962 /* The sordid relationship between focus_column and scroll_column:
3963  *
3964  * The focus_column represents the column that currently has keyboard focus, and
3965  * is used when navigating columns by keyboard.  scroll_column is used for
3966  * handling scrolling by keyboard, such that in cases.
3967  */
3968 static gint
3969 gtk_tree_view_focus (GtkWidget        *widget,
3970                      GtkDirectionType  direction)
3971 {
3972   GtkTreeView *tree_view;
3973   GtkWidget *focus_child;
3974   GtkContainer *container;
3975
3976   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3977   g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
3978
3979   container = GTK_CONTAINER (widget);
3980   tree_view = GTK_TREE_VIEW (widget);
3981
3982   if (!GTK_WIDGET_IS_SENSITIVE (container))
3983     return FALSE;
3984
3985   focus_child = container->focus_child;
3986
3987   /* Case 1.  Headers currently have focus. */
3988   if (focus_child)
3989     {
3990       switch (direction)
3991         {
3992         case GTK_DIR_LEFT:
3993         case GTK_DIR_RIGHT:
3994           gtk_tree_view_header_focus (tree_view, direction);
3995           return TRUE;
3996         case GTK_DIR_TAB_BACKWARD:
3997         case GTK_DIR_UP:
3998           return FALSE;
3999         case GTK_DIR_TAB_FORWARD:
4000         case GTK_DIR_DOWN:
4001           if (tree_view->priv->tree == NULL)
4002             return FALSE;
4003           gtk_tree_view_focus_to_cursor (tree_view);
4004           return TRUE;
4005         }
4006     }
4007
4008   /* Case 2. We don't have focus at all. */
4009   if (!GTK_WIDGET_HAS_FOCUS (container))
4010     {
4011       if (tree_view->priv->tree == NULL &&
4012           (direction == GTK_DIR_TAB_BACKWARD ||
4013            direction == GTK_DIR_UP))
4014         return gtk_tree_view_header_focus (tree_view, direction);
4015       if (((direction == GTK_DIR_TAB_FORWARD) ||
4016            (direction == GTK_DIR_RIGHT) ||
4017            (direction == GTK_DIR_DOWN) ||
4018            (direction == GTK_DIR_LEFT)) &&
4019           gtk_tree_view_header_focus (tree_view, direction))
4020         return TRUE;
4021
4022       if (tree_view->priv->tree == NULL)
4023         return FALSE;
4024       gtk_tree_view_focus_to_cursor (tree_view);
4025       return TRUE;
4026     }
4027
4028   /* Case 3. We have focus already. */
4029   if (tree_view->priv->tree == NULL)
4030     return gtk_tree_view_header_focus (tree_view, direction);
4031
4032   if (direction == GTK_DIR_TAB_BACKWARD)
4033     return (gtk_tree_view_header_focus (tree_view, direction));
4034   else if (direction == GTK_DIR_TAB_FORWARD)
4035     return FALSE;
4036
4037   /* Other directions caught by the keybindings */
4038   gtk_tree_view_focus_to_cursor (tree_view);
4039   return TRUE;
4040 }
4041
4042
4043 static void
4044 gtk_tree_view_set_focus_child (GtkContainer *container,
4045                                GtkWidget    *child)
4046 {
4047   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
4048   GList *list;
4049
4050   for (list = tree_view->priv->columns; list; list = list->next)
4051     {
4052       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
4053         {
4054           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
4055           break;
4056         }
4057     }
4058
4059   (* parent_class->set_focus_child) (container, child);
4060 }
4061
4062 static void
4063 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
4064                                GtkAdjustment *hadj,
4065                                GtkAdjustment *vadj)
4066 {
4067   gboolean need_adjust = FALSE;
4068
4069   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4070
4071   if (hadj)
4072     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
4073   else
4074     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4075   if (vadj)
4076     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
4077   else
4078     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
4079
4080   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
4081     {
4082       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
4083       gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
4084     }
4085
4086   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
4087     {
4088       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
4089       gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
4090     }
4091
4092   if (tree_view->priv->hadjustment != hadj)
4093     {
4094       tree_view->priv->hadjustment = hadj;
4095       gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
4096       gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
4097
4098       gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
4099                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4100                           tree_view);
4101       need_adjust = TRUE;
4102     }
4103
4104   if (tree_view->priv->vadjustment != vadj)
4105     {
4106       tree_view->priv->vadjustment = vadj;
4107       gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
4108       gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
4109
4110       gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
4111                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
4112                           tree_view);
4113       need_adjust = TRUE;
4114     }
4115
4116   if (need_adjust)
4117     gtk_tree_view_adjustment_changed (NULL, tree_view);
4118 }
4119
4120 static void
4121 gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view)
4122 {
4123   tree_view->priv->in_extended_selection = TRUE;
4124 }
4125
4126 static void
4127 gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view)
4128 {
4129   tree_view->priv->in_extended_selection = FALSE;
4130 }
4131
4132 static void
4133 gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view)
4134 {
4135   tree_view->priv->in_free_motion = TRUE;
4136 }
4137
4138 static void
4139 gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view)
4140 {
4141   tree_view->priv->in_free_motion = FALSE;
4142 }
4143
4144 static void
4145 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
4146                                 GtkMovementStep    step,
4147                                 gint               count)
4148 {
4149   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4150   g_return_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
4151                     step == GTK_MOVEMENT_VISUAL_POSITIONS ||
4152                     step == GTK_MOVEMENT_DISPLAY_LINES ||
4153                     step == GTK_MOVEMENT_PAGES ||
4154                     step == GTK_MOVEMENT_BUFFER_ENDS);
4155
4156   if (tree_view->priv->tree == NULL)
4157     return;
4158
4159   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
4160   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
4161
4162   switch (step)
4163     {
4164       /* currently we make no distinction.  When we go bi-di, we need to */
4165     case GTK_MOVEMENT_LOGICAL_POSITIONS:
4166     case GTK_MOVEMENT_VISUAL_POSITIONS:
4167       gtk_tree_view_move_cursor_left_right (tree_view, count);
4168       break;
4169     case GTK_MOVEMENT_DISPLAY_LINES:
4170       gtk_tree_view_move_cursor_up_down (tree_view, count);
4171       break;
4172     case GTK_MOVEMENT_PAGES:
4173       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
4174       break;
4175     case GTK_MOVEMENT_BUFFER_ENDS:
4176       gtk_tree_view_move_cursor_start_end (tree_view, count);
4177       break;
4178     default:
4179       g_assert_not_reached ();
4180     }
4181 }
4182
4183 /* TreeModel Callbacks
4184  */
4185
4186 static void
4187 gtk_tree_view_range_changed (GtkTreeModel *model,
4188                              GtkTreePath  *path,
4189                              GtkTreeIter  *iter,
4190                              GtkTreePath  *end_path,
4191                              GtkTreeIter  *end_iter,
4192                              gpointer      data)
4193 {
4194   GtkTreeView *tree_view = (GtkTreeView *)data;
4195   GtkRBTree *tree;
4196   GtkRBNode *node;
4197   gint height;
4198   gboolean dirty_marked;
4199   gboolean free_path = FALSE;
4200   gint vertical_separator;
4201
4202
4203   g_return_if_fail (path != NULL || iter != NULL);
4204
4205   gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
4206
4207   if (path == NULL)
4208     {
4209       path = gtk_tree_model_get_path (model, iter);
4210       free_path = TRUE;
4211     }
4212   else if (iter == NULL)
4213     gtk_tree_model_get_iter (model, iter, path);
4214
4215   if (_gtk_tree_view_find_node (tree_view,
4216                                 path,
4217                                 &tree,
4218                                 &node))
4219     /* We aren't actually showing the node */
4220     goto done;
4221
4222   if (tree == NULL)
4223     goto done;
4224
4225   dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
4226                                                     iter,
4227                                                     gtk_tree_path_get_depth (path),
4228                                                     &height);
4229
4230   if (GTK_RBNODE_GET_HEIGHT (node) != height + vertical_separator)
4231     {
4232       _gtk_rbtree_node_set_height (tree, node, height + vertical_separator);
4233       gtk_widget_queue_resize (GTK_WIDGET (data));
4234       goto done;
4235     }
4236   if (dirty_marked)
4237     gtk_widget_queue_resize (GTK_WIDGET (data));
4238   else
4239     gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
4240
4241  done:
4242   if (free_path)
4243     gtk_tree_path_free (path);
4244 }
4245
4246 static void
4247 gtk_tree_view_inserted (GtkTreeModel *model,
4248                         GtkTreePath  *path,
4249                         GtkTreeIter  *iter,
4250                         gpointer      data)
4251 {
4252   GtkTreeView *tree_view = (GtkTreeView *) data;
4253   gint *indices;
4254   GtkRBTree *tmptree, *tree;
4255   GtkRBNode *tmpnode = NULL;
4256   gint max_height;
4257   gint depth;
4258   gint i = 0;
4259   gboolean free_path = FALSE;
4260
4261   if (tree_view->priv->tree == NULL)
4262     tree_view->priv->tree = _gtk_rbtree_new ();
4263
4264   tmptree = tree = tree_view->priv->tree;
4265   g_return_if_fail (path != NULL || iter != NULL);
4266
4267   if (path == NULL)
4268     {
4269       path = gtk_tree_model_get_path (model, iter);
4270       free_path = TRUE;
4271     }
4272   else if (iter == NULL)
4273     gtk_tree_model_get_iter (model, iter, path);
4274
4275   /* Update all row-references */
4276   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
4277
4278   depth = gtk_tree_path_get_depth (path);
4279   indices = gtk_tree_path_get_indices (path);
4280
4281   /* First, find the parent tree */
4282   while (i < depth - 1)
4283     {
4284       if (tmptree == NULL)
4285         {
4286           /* We aren't showing the node */
4287           goto done;
4288         }
4289
4290       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
4291       if (tmpnode == NULL)
4292         {
4293           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
4294                      "This possibly means that a GtkTreeModel inserted a child node\n" \
4295                      "before the parent was inserted.");
4296           goto done;
4297         }
4298       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
4299         {
4300           /* FIXME enforce correct behavior on model, probably */
4301           /* In theory, the model should have emitted has_child_toggled here.  We
4302            * try to catch it anyway, just to be safe, in case the model hasn't.
4303            */
4304           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
4305                                                            tree,
4306                                                            tmpnode);
4307           gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
4308           gtk_tree_path_free (tmppath);
4309           goto done;
4310         }
4311
4312       tmptree = tmpnode->children;
4313       tree = tmptree;
4314       i++;
4315     }
4316
4317   if (tree == NULL)
4318     goto done;
4319
4320   /* ref the node */
4321   gtk_tree_model_ref_node (tree_view->priv->model, iter);
4322   max_height = gtk_tree_view_insert_iter_height (tree_view,
4323                                                  tree,
4324                                                  iter,
4325                                                  depth);
4326   if (indices[depth - 1] == 0)
4327     {
4328       tmpnode = _gtk_rbtree_find_count (tree, 1);
4329       _gtk_rbtree_insert_before (tree, tmpnode, max_height);
4330     }
4331   else
4332     {
4333       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
4334       _gtk_rbtree_insert_after (tree, tmpnode, max_height);
4335     }
4336
4337   _gtk_tree_view_update_size (tree_view);
4338
4339  done:
4340   if (free_path)
4341     gtk_tree_path_free (path);
4342 }
4343
4344 static void
4345 gtk_tree_view_has_child_toggled (GtkTreeModel *model,
4346                                  GtkTreePath  *path,
4347                                  GtkTreeIter  *iter,
4348                                  gpointer      data)
4349 {
4350   GtkTreeView *tree_view = (GtkTreeView *)data;
4351   GtkTreeIter real_iter;
4352   gboolean has_child;
4353   GtkRBTree *tree;
4354   GtkRBNode *node;
4355   gboolean free_path = FALSE;
4356
4357   g_return_if_fail (path != NULL || iter != NULL);
4358
4359   if (iter)
4360     real_iter = *iter;
4361
4362   if (path == NULL)
4363     {
4364       path = gtk_tree_model_get_path (model, iter);
4365       free_path = TRUE;
4366     }
4367   else if (iter == NULL)
4368     gtk_tree_model_get_iter (model, &real_iter, path);
4369
4370   if (_gtk_tree_view_find_node (tree_view,
4371                                 path,
4372                                 &tree,
4373                                 &node))
4374     /* We aren't actually showing the node */
4375     goto done;
4376
4377   if (tree == NULL)
4378     goto done;
4379
4380   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
4381   /* Sanity check.
4382    */
4383   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
4384     goto done;
4385
4386   if (has_child)
4387     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
4388   else
4389     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
4390
4391   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
4392     {
4393       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4394       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
4395         {
4396           GList *list;
4397
4398           for (list = tree_view->priv->columns; list; list = list->next)
4399             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
4400               {
4401                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
4402                 break;
4403               }
4404         }
4405       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4406     }
4407   else
4408     {
4409       /* FIXME: Just redraw the node */
4410       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4411     }
4412
4413  done:
4414   if (free_path)
4415     gtk_tree_path_free (path);
4416 }
4417
4418 static void
4419 count_children_helper (GtkRBTree *tree,
4420                        GtkRBNode *node,
4421                        gpointer   data)
4422 {
4423   if (node->children)
4424     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
4425   (*((gint *)data))++;
4426 }
4427
4428 static void
4429 gtk_tree_view_deleted (GtkTreeModel *model,
4430                        GtkTreePath  *path,
4431                        gpointer      data)
4432 {
4433   GtkTreeView *tree_view = (GtkTreeView *)data;
4434   GtkRBTree *tree;
4435   GtkRBNode *node;
4436   GList *list;
4437
4438   g_return_if_fail (path != NULL);
4439
4440   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
4441     return;
4442
4443   if (tree == NULL)
4444     return;
4445
4446   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
4447
4448   /* Change the selection */
4449   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4450     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
4451
4452   for (list = tree_view->priv->columns; list; list = list->next)
4453     if (((GtkTreeViewColumn *)list->data)->visible &&
4454         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4455       ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
4456
4457   /* Ensure we don't have a dangling pointer to a dead node */
4458   ensure_unprelighted (tree_view);
4459
4460   if (tree_view->priv->destroy_count_func)
4461     {
4462       gint child_count = 0;
4463       if (node->children)
4464         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
4465       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
4466     }
4467
4468   if (tree->root->count == 1)
4469     {
4470       if (tree_view->priv->tree == tree)
4471         tree_view->priv->tree = NULL;
4472
4473       _gtk_rbtree_remove (tree);
4474     }
4475   else
4476     {
4477       _gtk_rbtree_remove_node (tree, node);
4478     }
4479
4480   _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
4481 }
4482
4483
4484 static void
4485 gtk_tree_view_reordered (GtkTreeModel *model,
4486                          GtkTreePath  *parent,
4487                          GtkTreeIter  *iter,
4488                          gint         *new_order,
4489                          gpointer      data)
4490 {
4491   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
4492   GtkRBTree *tree;
4493   GtkRBNode *node;
4494   gint len;
4495
4496   len = gtk_tree_model_iter_n_children (model, iter);
4497
4498   if (len < 2)
4499     return;
4500
4501   gtk_tree_row_reference_reordered (G_OBJECT (data),
4502                                     parent,
4503                                     iter,
4504                                     new_order);
4505
4506   if (_gtk_tree_view_find_node (tree_view,
4507                                 parent,
4508                                 &tree,
4509                                 &node))
4510     return;
4511
4512   /* We need to special case the parent path */
4513   if (tree == NULL)
4514     tree = tree_view->priv->tree;
4515   else
4516     tree = node->children;
4517
4518   if (tree == NULL)
4519     return;
4520
4521   /* FIXME: we need to unprelight our tree, if it's prelit. */
4522   _gtk_rbtree_reorder (tree, new_order, len);
4523
4524   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4525 }
4526
4527
4528 /* Internal tree functions
4529  */
4530
4531
4532 static void
4533 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
4534                                      GtkRBTree         *tree,
4535                                      GtkTreeViewColumn *column,
4536                                      gint              *x1,
4537                                      gint              *x2)
4538 {
4539   GtkTreeViewColumn *tmp_column = NULL;
4540   gint total_width;
4541   GList *list;
4542
4543   if (x1)
4544     *x1 = 0;
4545
4546   if (x2)
4547     *x2 = 0;
4548
4549   total_width = 0;
4550   for (list = tree_view->priv->columns; list; list = list->next)
4551     {
4552       tmp_column = list->data;
4553
4554       if (tmp_column == column)
4555         break;
4556
4557       if (tmp_column->visible)
4558         total_width += tmp_column->width;
4559     }
4560
4561   if (tmp_column != column)
4562     {
4563       g_warning (G_STRLOC": passed-in column isn't in the tree");
4564       return;
4565     }
4566
4567   if (x1)
4568     *x1 = total_width;
4569
4570   if (x2)
4571     {
4572       if (column->visible)
4573         *x2 = total_width + column->width;
4574       else
4575         *x2 = total_width; /* width of 0 */
4576     }
4577 }
4578
4579 static void
4580 gtk_tree_view_get_cell_xrange (GtkTreeView       *tree_view,
4581                                GtkRBTree         *tree,
4582                                GtkTreeViewColumn *column,
4583                                gint              *x1,
4584                                gint              *x2)
4585 {
4586   GtkTreeViewColumn *tmp_column = NULL;
4587   gint total_width;
4588   GList *list;
4589
4590   if (x1)
4591     *x1 = 0;
4592
4593   if (x2)
4594     *x2 = 0;
4595
4596   total_width = 0;
4597   for (list = tree_view->priv->columns; list; list = list->next)
4598     {
4599       tmp_column = list->data;
4600
4601       if (tmp_column == column)
4602         break;
4603
4604       if (tmp_column->visible)
4605         total_width += tmp_column->width;
4606     }
4607
4608   if (tmp_column != column)
4609     {
4610       g_warning (G_STRLOC": passed-in column isn't in the tree");
4611       return;
4612     }
4613
4614   /* Remember we're getting the cell range, i.e. the cell_area passed
4615    * to the cell renderer.
4616    */
4617
4618   if (gtk_tree_view_is_expander_column (tree_view, column))
4619     total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
4620
4621   if (x1)
4622     *x1 = total_width;
4623
4624   if (x2)
4625     {
4626       if (column->visible)
4627         *x2 = total_width + column->displayed_width;
4628       else
4629         *x2 = total_width; /* width of 0 */
4630     }
4631 }
4632
4633 static void
4634 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
4635                                 gint        *x1,
4636                                 gint        *x2)
4637 {
4638   gint x_offset = 0;
4639   GList *list;
4640   GtkTreeViewColumn *tmp_column = NULL;
4641   gint total_width;
4642
4643   total_width = 0;
4644   for (list = tree_view->priv->columns; list; list = list->next)
4645     {
4646       tmp_column = list->data;
4647
4648       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
4649         {
4650           x_offset = total_width;
4651           break;
4652         }
4653
4654       if (tmp_column->visible)
4655         total_width += tmp_column->width;
4656     }
4657
4658   if (x1)
4659     *x1 = x_offset;
4660
4661   if (tmp_column && tmp_column->visible)
4662     {
4663       /* +1 because x2 isn't included in the range. */
4664       if (x2)
4665         *x2 = x_offset + tree_view->priv->tab_offset + 1;
4666     }
4667   else
4668     {
4669       /* return an empty range, the expander column is hidden */
4670       if (x2)
4671         *x2 = x_offset;
4672     }
4673 }
4674
4675 static void
4676 gtk_tree_view_setup_model (GtkTreeView *tree_view)
4677 {
4678   GtkTreePath *path;
4679   GtkTreeIter iter;
4680
4681   tree_view->priv->tree = NULL;
4682
4683   g_signal_connect (tree_view->priv->model,
4684                     "range_changed",
4685                     (GCallback) gtk_tree_view_range_changed,
4686                     tree_view);
4687   g_signal_connect (tree_view->priv->model,
4688                     "inserted",
4689                     (GCallback) gtk_tree_view_inserted,
4690                     tree_view);
4691   g_signal_connect (tree_view->priv->model,
4692                     "has_child_toggled",
4693                     (GCallback) gtk_tree_view_has_child_toggled,
4694                     tree_view);
4695   g_signal_connect (tree_view->priv->model,
4696                     "deleted",
4697                     (GCallback) gtk_tree_view_deleted,
4698                     tree_view);
4699   g_signal_connect (tree_view->priv->model,
4700                     "reordered",
4701                     (GCallback) gtk_tree_view_reordered,
4702                     tree_view);
4703
4704   if (tree_view->priv->columns == NULL)
4705     return;
4706
4707   path = gtk_tree_path_new_root ();
4708
4709   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
4710     {
4711       tree_view->priv->tree = _gtk_rbtree_new ();
4712       gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
4713     }
4714
4715   gtk_tree_path_free (path);
4716
4717   /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
4718
4719   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
4720 }
4721
4722 static gint
4723 gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
4724                                   GtkRBTree   *tree,
4725                                   GtkTreeIter *iter,
4726                                   gint         depth)
4727 {
4728   GtkTreeViewColumn *column;
4729   GList *list;
4730   gint max_height = 0;
4731   gint vertical_separator;
4732
4733   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4734   /* do stuff with node */
4735   for (list = tree_view->priv->columns; list; list = list->next)
4736     {
4737       gint height = 0, width = 0;
4738       column = list->data;
4739
4740       if (!column->visible)
4741         continue;
4742
4743       if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4744         continue;
4745
4746       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4747
4748       gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4749       max_height = MAX (max_height, vertical_separator + height);
4750
4751       if (gtk_tree_view_is_expander_column (tree_view, column) &&
4752           TREE_VIEW_DRAW_EXPANDERS (tree_view))
4753         _gtk_tree_view_column_set_width (column,
4754                                         MAX (column->width, depth * tree_view->priv->tab_offset + width));
4755       else
4756         _gtk_tree_view_column_set_width (column,
4757                                         MAX (column->width, width));
4758     }
4759   return max_height;
4760 }
4761
4762 static void
4763 gtk_tree_view_build_tree (GtkTreeView *tree_view,
4764                           GtkRBTree   *tree,
4765                           GtkTreeIter *iter,
4766                           gint         depth,
4767                           gboolean     recurse,
4768                           gboolean     calc_bounds)
4769 {
4770   GtkRBNode *temp = NULL;
4771   gint max_height;
4772
4773   do
4774     {
4775       max_height = 0;
4776       if (calc_bounds)
4777         max_height = gtk_tree_view_insert_iter_height (tree_view,
4778                                                        tree,
4779                                                        iter,
4780                                                        depth);
4781
4782       gtk_tree_model_ref_node (tree_view->priv->model, iter);
4783       temp = _gtk_rbtree_insert_after (tree, temp, max_height);
4784       if (recurse)
4785         {
4786           GtkTreeIter child;
4787
4788           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4789             {
4790               temp->children = _gtk_rbtree_new ();
4791               temp->children->parent_tree = tree;
4792               temp->children->parent_node = temp;
4793               gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
4794             }
4795         }
4796       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
4797         {
4798           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
4799             temp->flags ^= GTK_RBNODE_IS_PARENT;
4800           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
4801         }
4802     }
4803   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4804 }
4805
4806 static void
4807 gtk_tree_view_calc_size (GtkTreeView *tree_view,
4808                          GtkRBTree   *tree,
4809                          GtkTreeIter *iter,
4810                          gint         depth)
4811 {
4812   GtkRBNode *temp;
4813   GtkTreeIter child;
4814   GList *list;
4815   GtkTreeViewColumn *column;
4816   gint max_height;
4817   gint vertical_separator;
4818
4819   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4820
4821   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
4822
4823   temp = tree->root;
4824   while (temp->left != tree->nil)
4825     temp = temp->left;
4826
4827   do
4828     {
4829       max_height = 0;
4830       /* Do stuff with node */
4831       for (list = tree_view->priv->columns; list; list = list->next)
4832         {
4833           gint height = 0, width = 0;
4834           column = list->data;
4835
4836           if (!column->visible)
4837             continue;
4838
4839           gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4840           gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
4841           max_height = MAX (max_height, vertical_separator + height);
4842
4843           /* FIXME: I'm getting the width of all nodes here. )-: */
4844           if (column->dirty == FALSE)
4845             continue;
4846
4847           if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4848             {
4849               continue;
4850             }
4851           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4852               TREE_VIEW_DRAW_EXPANDERS (tree_view))
4853             _gtk_tree_view_column_set_width (column,
4854                                             MAX (column->width, depth * tree_view->priv->tab_offset + width));
4855           else
4856             _gtk_tree_view_column_set_width (column, MAX (column->width, width));
4857         }
4858
4859       _gtk_rbtree_node_set_height (tree, temp, max_height);
4860
4861       if (temp->children != NULL &&
4862           gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
4863         gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
4864       temp = _gtk_rbtree_next (tree, temp);
4865     }
4866   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4867 }
4868
4869 static gboolean
4870 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
4871                                    GtkTreeIter *iter,
4872                                    gint         depth,
4873                                    gint        *height)
4874 {
4875   GtkTreeViewColumn *column;
4876   GList *list;
4877   gboolean retval = FALSE;
4878   gint tmpheight;
4879
4880   if (height)
4881     *height = 0;
4882
4883   for (list = tree_view->priv->columns; list; list = list->next)
4884     {
4885       gint width;
4886       column = list->data;
4887       if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
4888         continue;
4889       if (!column->visible)
4890         continue;
4891
4892       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
4893
4894       if (height)
4895         {
4896           gtk_tree_view_column_cell_get_size (column,
4897                                               NULL, NULL, NULL,
4898                                               &width, &tmpheight);
4899           *height = MAX (*height, tmpheight);
4900         }
4901       else
4902         {
4903           gtk_tree_view_column_cell_get_size (column,
4904                                               NULL, NULL, NULL,
4905                                               &width, NULL);
4906         }
4907       if (gtk_tree_view_is_expander_column (tree_view, column) &&
4908           TREE_VIEW_DRAW_EXPANDERS (tree_view))
4909         {
4910           if (depth * tree_view->priv->tab_offset + width > column->width)
4911             {
4912               column->dirty = TRUE;
4913               retval = TRUE;
4914             }
4915         }
4916       else
4917         {
4918           if (width > column->width)
4919             {
4920               column->dirty = TRUE;
4921               retval = TRUE;
4922             }
4923         }
4924     }
4925
4926   return retval;
4927 }
4928
4929 static void
4930 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
4931                               GtkRBTree   *tree,
4932                               GtkTreeIter *iter,
4933                               gint         depth)
4934 {
4935   GtkRBNode *temp = tree->root;
4936   GtkTreeViewColumn *column;
4937   GList *list;
4938   GtkTreeIter child;
4939   gboolean is_all_dirty;
4940
4941   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
4942
4943   while (temp->left != tree->nil)
4944     temp = temp->left;
4945
4946   do
4947     {
4948       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
4949       is_all_dirty = TRUE;
4950       for (list = tree_view->priv->columns; list; list = list->next)
4951         {
4952           column = list->data;
4953           if (column->dirty == FALSE)
4954             {
4955               is_all_dirty = FALSE;
4956               break;
4957             }
4958         }
4959
4960       if (is_all_dirty)
4961         return;
4962
4963       gtk_tree_view_discover_dirty_iter (tree_view,
4964                                          iter,
4965                                          depth,
4966                                          FALSE);
4967       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
4968           temp->children != NULL)
4969         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
4970       temp = _gtk_rbtree_next (tree, temp);
4971     }
4972   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
4973 }
4974
4975
4976 static void
4977 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
4978 {
4979   GtkTreePath *path;
4980   gboolean dirty = FALSE;
4981   GList *list;
4982   GtkTreeViewColumn *column;
4983   GtkTreeIter iter;
4984
4985   if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
4986       tree_view->priv->model)
4987     gtk_tree_view_setup_model (tree_view);
4988
4989   for (list = tree_view->priv->columns; list; list = list->next)
4990     {
4991       column = list->data;
4992       if (column->dirty)
4993         {
4994           dirty = TRUE;
4995           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
4996             {
4997               gint w = 1;
4998
4999               if (column->button)
5000                 w = MAX (w, column->button->requisition.width);
5001
5002               _gtk_tree_view_column_set_width (column, w);
5003             }
5004         }
5005     }
5006
5007   if (dirty == FALSE)
5008     return;
5009
5010   if (tree_view->priv->model == NULL)
5011     return;
5012
5013   path = gtk_tree_path_new_root ();
5014   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
5015     {
5016       gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
5017       _gtk_tree_view_update_size (tree_view);
5018     }
5019
5020   gtk_tree_path_free (path);
5021
5022   for (list = tree_view->priv->columns; list; list = list->next)
5023     {
5024       column = list->data;
5025       column->dirty = FALSE;
5026     }
5027 }
5028
5029 /* Make sure the node is visible vertically */
5030 static void
5031 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
5032                                   GtkRBTree   *tree,
5033                                   GtkRBNode   *node)
5034 {
5035   gint offset;
5036
5037   /* We process updates because we want to clear old selected items when we scroll.
5038    * if this is removed, we get a "selection streak" at the bottom. */
5039   if (GTK_WIDGET_REALIZED (tree_view))
5040     gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
5041
5042   offset = _gtk_rbtree_node_find_offset (tree, node);
5043
5044   /* we reverse the order, b/c in the unusual case of the
5045    * node's height being taller then the visible area, we'd rather
5046    * have the node flush to the top
5047    */
5048   if (offset + GTK_RBNODE_GET_HEIGHT (node) >
5049       tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
5050     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5051                               offset + GTK_RBNODE_GET_HEIGHT (node) -
5052                               tree_view->priv->vadjustment->page_size);
5053   if (offset < tree_view->priv->vadjustment->value)
5054     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
5055                               offset);
5056
5057 }
5058
5059 /* This function could be more efficient.
5060  * I'll optimize it if profiling seems to imply that
5061  * it's important
5062  */
5063 GtkTreePath *
5064 _gtk_tree_view_find_path (GtkTreeView *tree_view,
5065                           GtkRBTree   *tree,
5066                           GtkRBNode   *node)
5067 {
5068   GtkTreePath *path;
5069   GtkRBTree *tmp_tree;
5070   GtkRBNode *tmp_node, *last;
5071   gint count;
5072
5073   path = gtk_tree_path_new ();
5074
5075   g_return_val_if_fail (node != NULL, path);
5076   g_return_val_if_fail (node != tree->nil, path);
5077
5078   count = 1 + node->left->count;
5079
5080   last = node;
5081   tmp_node = node->parent;
5082   tmp_tree = tree;
5083   while (tmp_tree)
5084     {
5085       while (tmp_node != tmp_tree->nil)
5086         {
5087           if (tmp_node->right == last)
5088             count += 1 + tmp_node->left->count;
5089           last = tmp_node;
5090           tmp_node = tmp_node->parent;
5091         }
5092       gtk_tree_path_prepend_index (path, count - 1);
5093       last = tmp_tree->parent_node;
5094       tmp_tree = tmp_tree->parent_tree;
5095       if (last)
5096         {
5097           count = 1 + last->left->count;
5098           tmp_node = last->parent;
5099         }
5100     }
5101   return path;
5102 }
5103
5104 /* Returns TRUE if we ran out of tree before finding the path.
5105  */
5106 gboolean
5107 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
5108                           GtkTreePath  *path,
5109                           GtkRBTree   **tree,
5110                           GtkRBNode   **node)
5111 {
5112   GtkRBNode *tmpnode = NULL;
5113   GtkRBTree *tmptree = tree_view->priv->tree;
5114   gint *indices = gtk_tree_path_get_indices (path);
5115   gint depth = gtk_tree_path_get_depth (path);
5116   gint i = 0;
5117
5118   *node = NULL;
5119   *tree = NULL;
5120
5121   if (depth == 0)
5122     return FALSE;
5123   do
5124     {
5125       if (tmptree == NULL)
5126         {
5127           *node = tmpnode;
5128           *tree = tmptree;
5129           return TRUE;
5130         }
5131       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5132       ++i;
5133       if (i >= depth)
5134         {
5135           *node = tmpnode;
5136           *tree = tmptree;
5137           return FALSE;
5138         }
5139       tmptree = tmpnode->children;
5140     }
5141   while (1);
5142 }
5143
5144 static gboolean
5145 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
5146                                   GtkTreeViewColumn *column)
5147 {
5148   GList *list;
5149
5150   if (tree_view->priv->expander_column != NULL)
5151     {
5152       if (tree_view->priv->expander_column == column)
5153         return TRUE;
5154       return FALSE;
5155     }
5156   else
5157     {
5158       for (list = tree_view->priv->columns; list; list = list->next)
5159         if (((GtkTreeViewColumn *)list->data)->visible)
5160           break;
5161       if (list && list->data == column)
5162         return TRUE;
5163     }
5164   return FALSE;
5165 }
5166
5167 static void
5168 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
5169                                 guint           keyval,
5170                                 guint           modmask,
5171                                 GtkMovementStep step,
5172                                 gint            count)
5173 {
5174
5175   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
5176                                 "move_cursor", 2,
5177                                 GTK_TYPE_ENUM, step,
5178                                 GTK_TYPE_INT, count);
5179
5180   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
5181                                 "move_cursor", 2,
5182                                 GTK_TYPE_ENUM, step,
5183                                 GTK_TYPE_INT, count);
5184
5185   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
5186    return;
5187
5188   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
5189                                 "move_cursor", 2,
5190                                 GTK_TYPE_ENUM, step,
5191                                 GTK_TYPE_INT, count);
5192
5193   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
5194                                 "move_cursor", 2,
5195                                 GTK_TYPE_ENUM, step,
5196                                 GTK_TYPE_INT, count);
5197 }
5198
5199 static gint
5200 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
5201                                  GtkTreeIter  *iter,
5202                                  GtkRBTree    *tree,
5203                                  GtkRBNode    *node)
5204 {
5205   gint retval = FALSE;
5206   do
5207     {
5208       g_return_val_if_fail (node != NULL, FALSE);
5209
5210       if (node->children)
5211         {
5212           GtkTreeIter child;
5213           GtkRBTree *new_tree;
5214           GtkRBNode *new_node;
5215
5216           new_tree = node->children;
5217           new_node = new_tree->root;
5218
5219           while (new_node && new_node->left != new_tree->nil)
5220             new_node = new_node->left;
5221
5222           g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE);
5223           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
5224         }
5225
5226       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
5227         retval = TRUE;
5228       gtk_tree_model_unref_node (model, iter);
5229       node = _gtk_rbtree_next (tree, node);
5230     }
5231   while (gtk_tree_model_iter_next (model, iter));
5232
5233   return retval;
5234 }
5235
5236 static gint
5237 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
5238                                               GtkRBTree   *tree)
5239 {
5240   GtkTreeIter iter;
5241   GtkTreePath *path;
5242   GtkRBNode *node;
5243   gint retval;
5244
5245   node = tree->root;
5246   while (node && node->left != tree->nil)
5247     node = node->left;
5248
5249   g_return_val_if_fail (node != NULL, FALSE);
5250   path = _gtk_tree_view_find_path (tree_view, tree, node);
5251   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
5252                            &iter, path);
5253   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
5254   gtk_tree_path_free (path);
5255
5256   return retval;
5257 }
5258
5259 static void
5260 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
5261                                     GtkTreeViewColumn *column)
5262 {
5263   GtkTreeViewColumn *left_column;
5264   GtkTreeViewColumn *cur_column = NULL;
5265   GtkTreeViewColumnReorder *reorder;
5266
5267   GList *tmp_list;
5268   gint left;
5269
5270   /* We want to precalculate the motion list such that we know what column slots
5271    * are available.
5272    */
5273   left_column = NULL;
5274
5275   /* First, identify all possible drop spots */
5276   tmp_list = tree_view->priv->columns;
5277
5278   while (tmp_list)
5279     {
5280       g_assert (tmp_list);
5281
5282       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5283       tmp_list = tmp_list->next;
5284
5285       if (cur_column->visible == FALSE)
5286         continue;
5287
5288       /* If it's not the column moving and func tells us to skip over the column, we continue. */
5289       if (left_column != column && cur_column != column &&
5290           tree_view->priv->column_drop_func &&
5291           ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5292         {
5293           left_column = cur_column;
5294           continue;
5295         }
5296       reorder = g_new (GtkTreeViewColumnReorder, 1);
5297       reorder->left_column = left_column;
5298       left_column = reorder->right_column = cur_column;
5299
5300       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5301     }
5302
5303   /* Add the last one */
5304   if (tree_view->priv->column_drop_func == NULL ||
5305       ((left_column != column) &&
5306        (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
5307     {
5308       reorder = g_new (GtkTreeViewColumnReorder, 1);
5309       reorder->left_column = left_column;
5310       reorder->right_column = NULL;
5311       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
5312     }
5313
5314   /* We quickly check to see if it even makes sense to reorder columns. */
5315   /* If there is nothing that can be moved, then we return */
5316
5317   if (tree_view->priv->column_drag_info == NULL)
5318     return;
5319
5320   /* We know there are always 2 slots possbile, as you can always return column. */
5321   /* If that's all there is, return */
5322   if (tree_view->priv->column_drag_info->next->next == NULL &&
5323       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
5324       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
5325     {
5326       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5327         g_free (tmp_list->data);
5328       g_list_free (tree_view->priv->column_drag_info);
5329       tree_view->priv->column_drag_info = NULL;
5330       return;
5331     }
5332   /* We fill in the ranges for the columns, now that we've isolated them */
5333   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5334
5335   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
5336     {
5337       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
5338
5339       reorder->left_align = left;
5340       if (tmp_list->next != NULL)
5341         {
5342           g_assert (tmp_list->next->data);
5343           left = reorder->right_align = (reorder->right_column->button->allocation.x +
5344                                          reorder->right_column->button->allocation.width +
5345                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
5346         }
5347       else
5348         {
5349           gint width;
5350
5351           gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
5352           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
5353         }
5354     }
5355 }
5356
5357 void
5358 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
5359                                   GtkTreeViewColumn *column)
5360 {
5361   GdkEvent send_event;
5362   GtkAllocation allocation;
5363   gint x, y, width, height;
5364
5365   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
5366
5367   gtk_tree_view_set_column_drag_info (tree_view, column);
5368
5369   if (tree_view->priv->column_drag_info == NULL)
5370     return;
5371
5372   if (tree_view->priv->drag_window == NULL)
5373     {
5374       GdkWindowAttr attributes;
5375       guint attributes_mask;
5376
5377       attributes.window_type = GDK_WINDOW_CHILD;
5378       attributes.wclass = GDK_INPUT_OUTPUT;
5379       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
5380       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
5381       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
5382       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
5383
5384       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
5385                                                      &attributes,
5386                                                      attributes_mask);
5387       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
5388     }
5389
5390   gdk_pointer_ungrab (GDK_CURRENT_TIME);
5391   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5392
5393   gtk_grab_remove (column->button);
5394
5395   send_event.crossing.type = GDK_LEAVE_NOTIFY;
5396   send_event.crossing.send_event = TRUE;
5397   send_event.crossing.window = column->button->window;
5398   send_event.crossing.subwindow = NULL;
5399   send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
5400   send_event.crossing.time = GDK_CURRENT_TIME;
5401
5402   gtk_propagate_event (column->button, &send_event);
5403
5404   send_event.button.type = GDK_BUTTON_RELEASE;
5405   send_event.button.window = GDK_ROOT_PARENT ();
5406   send_event.button.send_event = TRUE;
5407   send_event.button.time = GDK_CURRENT_TIME;
5408   send_event.button.x = -1;
5409   send_event.button.y = -1;
5410   send_event.button.axes = NULL;
5411   send_event.button.state = 0;
5412   send_event.button.button = 1;
5413   send_event.button.device = gdk_core_pointer;
5414   send_event.button.x_root = 0;
5415   send_event.button.y_root = 0;
5416
5417   gtk_propagate_event (column->button, &send_event);
5418
5419   gdk_window_move_resize (tree_view->priv->drag_window,
5420                           column->button->allocation.x,
5421                           column->button->allocation.y + column->button->allocation.height,
5422                           column->button->allocation.width,
5423                           column->button->allocation.height);
5424   gdk_window_reparent (column->button->window, tree_view->priv->drag_window, 0, 0);
5425   tree_view->priv->drag_column_x = column->button->allocation.x;
5426   allocation = column->button->allocation;
5427   allocation.x = 0;
5428   gtk_widget_size_allocate (column->button, &allocation);
5429   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
5430
5431   tree_view->priv->drag_column = column;
5432   gdk_window_show (tree_view->priv->drag_window);
5433
5434   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
5435   gdk_window_get_size (tree_view->priv->header_window, &width, &height);
5436
5437   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5438   while (gtk_events_pending ())
5439     gtk_main_iteration ();
5440
5441   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
5442   gdk_pointer_grab (tree_view->priv->drag_window,
5443                     FALSE,
5444                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
5445                     NULL, NULL, GDK_CURRENT_TIME);
5446   gdk_keyboard_grab (tree_view->priv->drag_window,
5447                      FALSE,
5448                      GDK_CURRENT_TIME);
5449
5450 }
5451
5452 static void
5453 gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
5454                                GtkRBTree    *tree,
5455                                GtkRBNode    *node,
5456                                GdkRectangle *clip_rect)
5457 {
5458   GdkRectangle rect;
5459
5460   if (!GTK_WIDGET_REALIZED (tree_view))
5461     return;
5462
5463   rect.x = 0;
5464   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
5465
5466   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
5467   rect.height = BACKGROUND_HEIGHT (node);
5468
5469   if (clip_rect)
5470     {
5471       GdkRectangle new_rect;
5472
5473       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
5474
5475       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
5476     }
5477   else
5478     {
5479       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
5480     }
5481 }
5482
5483 static void
5484 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
5485                                GtkTreePath      *path,
5486                                GdkRectangle     *clip_rect)
5487 {
5488   GtkRBTree *tree = NULL;
5489   GtkRBNode *node = NULL;
5490
5491   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5492
5493   if (tree)
5494     gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
5495 }
5496
5497 /* x and y are the mouse position
5498  */
5499 static void
5500 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
5501                           GtkRBTree   *tree,
5502                           GtkRBNode   *node,
5503                           gint         x,
5504                           gint         y)
5505 {
5506   GdkRectangle area;
5507   GtkStateType state;
5508   GtkWidget *widget;
5509   gint x_offset = 0;
5510   gint vertical_separator;
5511   gint expander_height;
5512
5513   gtk_widget_style_get (GTK_WIDGET (tree_view),
5514                         "vertical_separator", &vertical_separator,
5515                         "expander_height", &expander_height,
5516                         NULL);
5517
5518   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
5519     return;
5520
5521   widget = GTK_WIDGET (tree_view);
5522
5523   gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
5524
5525   area.x = x_offset;
5526   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
5527   area.width = tree_view->priv->tab_offset - 2;
5528   area.height = CELL_HEIGHT (node, vertical_separator);
5529
5530   if (node == tree_view->priv->button_pressed_node)
5531     {
5532       if (x >= area.x && x <= (area.x + area.width) &&
5533           y >= area.y && y <= (area.y + area.height))
5534         state = GTK_STATE_ACTIVE;
5535       else
5536         state = GTK_STATE_NORMAL;
5537     }
5538   else
5539     {
5540       if (node == tree_view->priv->prelight_node &&
5541           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
5542         state = GTK_STATE_PRELIGHT;
5543       else
5544         state = GTK_STATE_NORMAL;
5545     }
5546
5547   gtk_paint_expander (widget->style,
5548                       tree_view->priv->bin_window,
5549                       state,
5550                       &area,
5551                       widget,
5552                       "treeview",
5553                       area.x,
5554                       (area.y + (area.height - expander_height) / 2 - (area.height + 1) % 2),
5555                       node->children != NULL);
5556 }
5557
5558
5559 static void
5560 _gtk_tree_view_update_col_width (GtkTreeView *tree_view)
5561 {
5562   GList *list, *last_column;
5563   GtkTreeViewColumn *column;
5564   gint width = 0;
5565
5566   for (last_column = g_list_last (tree_view->priv->columns);
5567        last_column &&
5568          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
5569          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
5570        last_column = last_column->prev)
5571     ;
5572
5573   if (last_column == NULL)
5574     return;
5575
5576   for (list = tree_view->priv->columns; list != last_column; list = list->next)
5577     {
5578       column = GTK_TREE_VIEW_COLUMN (list->data);
5579       if (! column->visible)
5580         continue;
5581
5582       width += column->width;
5583       column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
5584     }
5585   column = GTK_TREE_VIEW_COLUMN (last_column->data);
5586   column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
5587 }
5588
5589 static void
5590 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
5591
5592 {
5593   GtkTreePath *cursor_path;
5594
5595   if ((tree_view->priv->tree == NULL) ||
5596       (! GTK_WIDGET_REALIZED (tree_view)))
5597     return;
5598
5599   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
5600   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5601
5602   cursor_path = NULL;
5603   if (tree_view->priv->cursor)
5604     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5605
5606   if (cursor_path == NULL)
5607     {
5608       GtkTreePath *tmp_path = gtk_tree_path_new_root ();
5609       /* FIXME: Get the first one visible!!! */
5610       if (tree_view->priv->cursor)
5611         gtk_tree_row_reference_free (tree_view->priv->cursor);
5612
5613       tree_view->priv->cursor =
5614         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
5615       cursor_path = tmp_path;
5616     }
5617
5618   if (tree_view->priv->selection->type == GTK_TREE_SELECTION_SINGLE)
5619     gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
5620   else
5621     gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
5622   gtk_tree_path_free (cursor_path);
5623 }
5624
5625 static void
5626 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
5627                                    gint         count)
5628 {
5629   GtkRBTree *cursor_tree = NULL;
5630   GtkRBNode *cursor_node = NULL;
5631   GtkRBTree *new_cursor_tree = NULL;
5632   GtkRBNode *new_cursor_node = NULL;
5633   GtkTreePath *cursor_path = NULL;
5634
5635   cursor_path = NULL;
5636   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
5637     return;
5638
5639   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5640   _gtk_tree_view_find_node (tree_view, cursor_path,
5641                             &cursor_tree, &cursor_node);
5642   gtk_tree_path_free (cursor_path);
5643
5644   if (count == -1)
5645     _gtk_rbtree_prev_full (cursor_tree, cursor_node,
5646                            &new_cursor_tree, &new_cursor_node);
5647   else
5648     _gtk_rbtree_next_full (cursor_tree, cursor_node,
5649                            &new_cursor_tree, &new_cursor_node);
5650
5651   if (new_cursor_node)
5652     {
5653       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
5654       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
5655       gtk_tree_path_free (cursor_path);
5656     }
5657   else
5658     {
5659       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5660     }
5661
5662   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5663 }
5664
5665 static void
5666 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
5667                                         gint         count)
5668 {
5669   GtkRBTree *cursor_tree = NULL;
5670   GtkRBNode *cursor_node = NULL;
5671   GtkTreePath *cursor_path = NULL;
5672   gint y;
5673   gint vertical_separator;
5674
5675   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
5676     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5677   else
5678     /* This is sorta weird.  Focus in should give us a cursor */
5679     return;
5680
5681   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5682   _gtk_tree_view_find_node (tree_view, cursor_path,
5683                             &cursor_tree, &cursor_node);
5684
5685   gtk_tree_path_free (cursor_path);
5686
5687   g_return_if_fail (cursor_node != NULL);
5688
5689   y = CELL_FIRST_PIXEL (tree_view, cursor_tree, cursor_node, vertical_separator);
5690   y += count * tree_view->priv->vadjustment->page_size;
5691   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
5692
5693   _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
5694   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5695   g_return_if_fail (cursor_path != NULL);
5696   gtk_tree_view_real_set_cursor (tree_view,
5697                                  cursor_path,
5698                                  TRUE);
5699 }
5700
5701 static void
5702 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
5703                                       gint         count)
5704 {
5705   GtkRBTree *cursor_tree = NULL;
5706   GtkRBNode *cursor_node = NULL;
5707   GtkTreePath *cursor_path = NULL;
5708
5709   g_print ("gtk_tree_view_move_cursor_left_right\n");
5710
5711   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
5712     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5713   else
5714     return;
5715
5716   _gtk_tree_view_find_node (tree_view, cursor_path,
5717                             &cursor_tree, &cursor_node);
5718   gtk_tree_path_free (cursor_path);
5719
5720
5721 }
5722
5723 static void
5724 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
5725                                      gint         count)
5726 {
5727   GtkRBTree *cursor_tree;
5728   GtkRBNode *cursor_node;
5729   GtkTreePath *path;
5730
5731   g_return_if_fail (tree_view->priv->tree != NULL);
5732
5733   if (count == -1)
5734     {
5735       cursor_tree = tree_view->priv->tree;
5736       cursor_node = cursor_tree->root;
5737       while (cursor_node && cursor_node->left != cursor_tree->nil)
5738         cursor_node = cursor_node->left;
5739     }
5740   else
5741     {
5742       cursor_tree = tree_view->priv->tree;
5743       cursor_node = cursor_tree->root;
5744       do
5745         {
5746           while (cursor_node && cursor_node->right != cursor_tree->nil)
5747             cursor_node = cursor_node->right;
5748           if (cursor_node->children == NULL)
5749             break;
5750
5751           cursor_tree = cursor_node->children;
5752           cursor_node = cursor_tree->root;
5753         }
5754       while (1);
5755     }
5756
5757   path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
5758   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5759                                             cursor_node,
5760                                             cursor_tree,
5761                                             path,
5762                                             FALSE?GDK_SHIFT_MASK:0);
5763
5764   gtk_tree_row_reference_free (tree_view->priv->cursor);
5765   tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
5766   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5767 }
5768
5769 static void
5770 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view)
5771 {
5772   GtkRBTree *cursor_tree = NULL;
5773   GtkRBNode *cursor_node = NULL;
5774   GtkTreePath *cursor_path = NULL;
5775
5776   cursor_path = NULL;
5777   if (tree_view->priv->cursor)
5778     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5779
5780   if (cursor_path == NULL)
5781     return;
5782
5783   _gtk_tree_view_find_node (tree_view, cursor_path,
5784                             &cursor_tree, &cursor_node);
5785   if (cursor_tree == NULL)
5786     return;
5787
5788   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5789                                             cursor_node,
5790                                             cursor_tree,
5791                                             cursor_path,
5792                                             0);
5793
5794   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5795
5796   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5797   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5798   gtk_tree_path_free (cursor_path);
5799 }
5800
5801 static void
5802 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
5803 {
5804   GtkRBTree *cursor_tree = NULL;
5805   GtkRBNode *cursor_node = NULL;
5806   GtkTreePath *cursor_path = NULL;
5807
5808   cursor_path = NULL;
5809   if (tree_view->priv->cursor)
5810     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5811
5812   if (cursor_path == NULL)
5813     return;
5814
5815   _gtk_tree_view_find_node (tree_view, cursor_path,
5816                             &cursor_tree, &cursor_node);
5817   if (cursor_tree == NULL)
5818     return;
5819
5820   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5821                                             cursor_node,
5822                                             cursor_tree,
5823                                             cursor_path,
5824                                             GDK_CONTROL_MASK);
5825
5826   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5827
5828   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5829   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5830   gtk_tree_path_free (cursor_path);
5831 }
5832
5833
5834
5835 static void
5836 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
5837                                                gboolean     logical,
5838                                                gboolean     expand,
5839                                                gboolean     open_all)
5840 {
5841   GtkTreePath *cursor_path = NULL;
5842
5843   cursor_path = NULL;
5844   if (tree_view->priv->cursor)
5845     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5846
5847   if (cursor_path == NULL)
5848     return;
5849
5850   if (expand)
5851     gtk_tree_view_expand_row (tree_view, cursor_path, open_all);
5852   else
5853     gtk_tree_view_collapse_row (tree_view, cursor_path);
5854
5855   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5856   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5857   gtk_tree_path_free (cursor_path);
5858 }
5859
5860 static void
5861 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
5862 {
5863   GtkRBTree *cursor_tree = NULL;
5864   GtkRBNode *cursor_node = NULL;
5865   GtkTreePath *cursor_path = NULL;
5866
5867   cursor_path = NULL;
5868   if (tree_view->priv->cursor)
5869     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
5870
5871   if (cursor_path == NULL)
5872     return;
5873
5874   _gtk_tree_view_find_node (tree_view, cursor_path,
5875                             &cursor_tree, &cursor_node);
5876   if (cursor_tree == NULL)
5877     return;
5878
5879   if (cursor_tree->parent_node)
5880     {
5881       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5882       cursor_node = cursor_tree->parent_node;
5883       cursor_tree = cursor_tree->parent_tree;
5884
5885       gtk_tree_path_up (cursor_path);
5886       gtk_tree_row_reference_free (tree_view->priv->cursor);
5887       tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
5888       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
5889                                                 cursor_node,
5890                                                 cursor_tree,
5891                                                 cursor_path,
5892                                                 0);
5893     }
5894
5895   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
5896
5897   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5898   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
5899   gtk_tree_path_free (cursor_path);
5900 }
5901
5902 void
5903 _gtk_tree_view_update_size (GtkTreeView *tree_view)
5904 {
5905   gint width, height;
5906   GList *list;
5907   GtkTreeViewColumn *column;
5908   gint vertical_separator;
5909   gint i;
5910
5911   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
5912
5913   if (tree_view->priv->model == NULL)
5914     {
5915       tree_view->priv->width = 0;
5916       tree_view->priv->height = 0;
5917       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5918       return;
5919     }
5920
5921   width = 0;
5922   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
5923     {
5924       column = list->data;
5925       if (!column->visible)
5926         continue;
5927       width += TREE_VIEW_COLUMN_WIDTH (column);
5928     }
5929
5930   if (tree_view->priv->tree == NULL)
5931     height = 0;
5932   else
5933     height = tree_view->priv->tree->root->offset + vertical_separator;
5934
5935   if (tree_view->priv->width != width)
5936     {
5937       tree_view->priv->width = width;
5938       tree_view->priv->hadjustment->upper = width;
5939       gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
5940     }
5941
5942   if (tree_view->priv->height != height)
5943     {
5944       tree_view->priv->height = height;
5945       tree_view->priv->vadjustment->upper = tree_view->priv->height;
5946       gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
5947     }
5948
5949   if (GTK_WIDGET_REALIZED (tree_view))
5950     {
5951       gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
5952       gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
5953
5954       _gtk_tree_view_update_col_width (tree_view);
5955     }
5956
5957   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5958 }
5959
5960 /* this function returns the new width of the column being resized given
5961  * the column and x position of the cursor; the x cursor position is passed
5962  * in as a pointer and automagicly corrected if it's beyond min/max limits
5963  */
5964 static gint
5965 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
5966                                 gint       i,
5967                                 gint      *x)
5968 {
5969   GtkTreeViewColumn *column;
5970   gint width;
5971
5972   /* first translate the x position from widget->window
5973    * to clist->clist_window
5974    */
5975
5976   column = g_list_nth (tree_view->priv->columns, i)->data;
5977   width = *x - column->button->allocation.x;
5978
5979   /* Clamp down the value */
5980   if (column->min_width == -1)
5981     width = MAX (column->button->requisition.width,
5982                  width);
5983   else
5984     width = MAX (column->min_width,
5985                  width);
5986   if (column->max_width != -1)
5987     width = MIN (width, column->max_width != -1);
5988   *x = column->button->allocation.x + width;
5989
5990   return width;
5991 }
5992
5993
5994 /* Callbacks */
5995 static void
5996 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
5997                                   GtkTreeView   *tree_view)
5998 {
5999   if (GTK_WIDGET_REALIZED (tree_view))
6000     {
6001       gdk_window_move (tree_view->priv->bin_window,
6002                        - tree_view->priv->hadjustment->value,
6003                        - tree_view->priv->vadjustment->value);
6004       gdk_window_move (tree_view->priv->header_window,
6005                        - tree_view->priv->hadjustment->value,
6006                        0);
6007
6008       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6009       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
6010     }
6011 }
6012
6013 \f
6014
6015 /* Public methods
6016  */
6017
6018 /**
6019  * gtk_tree_view_new:
6020  *
6021  * Creates a new #GtkTreeView widget.
6022  *
6023  * Return value: A newly created #GtkTreeView widget.
6024  **/
6025 GtkWidget *
6026 gtk_tree_view_new (void)
6027 {
6028   GtkTreeView *tree_view;
6029
6030   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6031
6032   return GTK_WIDGET (tree_view);
6033 }
6034
6035 /**
6036  * gtk_tree_view_new_with_model:
6037  * @model: the model.
6038  *
6039  * Creates a new #GtkTreeView widget with the model initialized to @model.
6040  *
6041  * Return value: A newly created #GtkTreeView widget.
6042  **/
6043 GtkWidget *
6044 gtk_tree_view_new_with_model (GtkTreeModel *model)
6045 {
6046   GtkTreeView *tree_view;
6047
6048   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
6049   gtk_tree_view_set_model (tree_view, model);
6050
6051   return GTK_WIDGET (tree_view);
6052 }
6053
6054 /* Public Accessors
6055  */
6056
6057 /**
6058  * gtk_tree_view_get_model:
6059  * @tree_view: a #GtkTreeView
6060  *
6061  * Returns the model the the #GtkTreeView is based on.  Returns NULL if the
6062  * model is unset.
6063  *
6064  * Return value: A #GtkTreeModel, or NULL if none is currently being used.
6065  **/
6066 GtkTreeModel *
6067 gtk_tree_view_get_model (GtkTreeView *tree_view)
6068 {
6069   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6070
6071   return tree_view->priv->model;
6072 }
6073
6074 /**
6075  * gtk_tree_view_set_model:
6076  * @tree_view: A #GtkTreeNode.
6077  * @model: The model.
6078  *
6079  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
6080  * set, it will remove it before setting the new model.  If @model is NULL, then
6081  * it will unset the old model.
6082  **/
6083 void
6084 gtk_tree_view_set_model (GtkTreeView  *tree_view,
6085                          GtkTreeModel *model)
6086 {
6087   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6088
6089   if (model == tree_view->priv->model)
6090     return;
6091
6092   if (model != NULL)
6093     g_object_ref (model);
6094
6095   if (tree_view->priv->model != NULL)
6096     {
6097       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
6098         {
6099           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6100                                                 G_SIGNAL_MATCH_DATA,
6101                                                 0, 0, NULL,
6102                                                 NULL, tree_view);
6103           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6104                                                 G_SIGNAL_MATCH_DATA,
6105                                                 0, 0, NULL,
6106                                                 NULL, tree_view);
6107           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6108                                                 G_SIGNAL_MATCH_DATA,
6109                                                 0, 0, NULL,
6110                                                 NULL, tree_view);
6111           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6112                                                 G_SIGNAL_MATCH_DATA,
6113                                                 0, 0, NULL,
6114                                                 NULL, tree_view);
6115           g_signal_handlers_disconnect_matched (G_OBJECT (tree_view->priv->model),
6116                                                 G_SIGNAL_MATCH_DATA,
6117                                                 0, 0, NULL,
6118                                                 NULL, tree_view);
6119           if (tree_view->priv->tree)
6120             _gtk_rbtree_free (tree_view->priv->tree);
6121         }
6122
6123       if (tree_view->priv->drag_dest_row)
6124         gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
6125
6126       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
6127       g_object_unref (tree_view->priv->model);
6128     }
6129
6130   tree_view->priv->model = model;
6131
6132   if (model == NULL)
6133     {
6134       tree_view->priv->tree = NULL;
6135       if (GTK_WIDGET_REALIZED (tree_view))
6136         _gtk_tree_view_update_size (tree_view);
6137     }
6138   else if (GTK_WIDGET_REALIZED (tree_view))
6139     {
6140       gtk_tree_view_setup_model (tree_view);
6141       _gtk_tree_view_update_size (tree_view);
6142     }
6143
6144   g_object_notify (G_OBJECT (tree_view), "model");
6145 }
6146
6147 /**
6148  * gtk_tree_view_get_selection:
6149  * @tree_view: A #GtkTreeView.
6150  *
6151  * Gets the #GtkTreeSelection associated with @tree_view.
6152  *
6153  * Return value: A #GtkTreeSelection object.
6154  **/
6155 GtkTreeSelection *
6156 gtk_tree_view_get_selection (GtkTreeView *tree_view)
6157 {
6158   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6159
6160   return tree_view->priv->selection;
6161 }
6162
6163 /**
6164  * gtk_tree_view_get_hadjustment:
6165  * @tree_view: A #GtkTreeView
6166  *
6167  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
6168  *
6169  * Return value: A #GtkAdjustment object, or NULL if none is currently being
6170  * used.
6171  **/
6172 GtkAdjustment *
6173 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
6174 {
6175   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6176
6177   if (tree_view->priv->hadjustment == NULL)
6178     gtk_tree_view_set_hadjustment (tree_view, NULL);
6179
6180   return tree_view->priv->hadjustment;
6181 }
6182
6183 /**
6184  * gtk_tree_view_set_hadjustment:
6185  * @tree_view: A #GtkTreeView
6186  * @adjustment: The #GtkAdjustment to set, or NULL
6187  *
6188  * Sets the #GtkAdjustment for the current horizontal aspect.
6189  **/
6190 void
6191 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
6192                                GtkAdjustment *adjustment)
6193 {
6194   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6195
6196   gtk_tree_view_set_adjustments (tree_view,
6197                                  adjustment,
6198                                  tree_view->priv->vadjustment);
6199
6200   g_object_notify (G_OBJECT (tree_view), "hadjustment");
6201 }
6202
6203 /**
6204  * gtk_tree_view_get_vadjustment:
6205  * @tree_view: A #GtkTreeView
6206  *
6207  * Gets the #GtkAdjustment currently being used for the vertical aspect.
6208  *
6209  * Return value: A #GtkAdjustment object, or NULL if none is currently being
6210  * used.
6211  **/
6212 GtkAdjustment *
6213 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
6214 {
6215   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6216
6217   if (tree_view->priv->vadjustment == NULL)
6218     gtk_tree_view_set_vadjustment (tree_view, NULL);
6219
6220   return tree_view->priv->vadjustment;
6221 }
6222
6223 /**
6224  * gtk_tree_view_set_vadjustment:
6225  * @tree_view: A #GtkTreeView
6226  * @adjustment: The #GtkAdjustment to set, or NULL
6227  *
6228  * Sets the #GtkAdjustment for the current vertical aspect.
6229  **/
6230 void
6231 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
6232                                GtkAdjustment *adjustment)
6233 {
6234   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6235
6236   gtk_tree_view_set_adjustments (tree_view,
6237                                  tree_view->priv->hadjustment,
6238                                  adjustment);
6239
6240   g_object_notify (G_OBJECT (tree_view), "vadjustment");
6241 }
6242
6243 /* Column and header operations */
6244
6245 /**
6246  * gtk_tree_view_get_headers_visible:
6247  * @tree_view: A #GtkTreeView.
6248  *
6249  * Returns TRUE if the headers on the @tree_view are visible.
6250  *
6251  * Return value: Whether the headers are visible or not.
6252  **/
6253 gboolean
6254 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
6255 {
6256   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6257
6258   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6259 }
6260
6261 /**
6262  * gtk_tree_view_set_headers_visible:
6263  * @tree_view: A #GtkTreeView.
6264  * @headers_visible: TRUE if the headers are visible
6265  *
6266  * Sets the the visibility state of the headers.
6267  **/
6268 void
6269 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
6270                                    gboolean     headers_visible)
6271 {
6272   gint x, y;
6273   GList *list;
6274   GtkTreeViewColumn *column;
6275
6276   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6277
6278   headers_visible = !! headers_visible;
6279
6280   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
6281     return;
6282
6283   if (headers_visible)
6284     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6285   else
6286     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
6287
6288   if (GTK_WIDGET_REALIZED (tree_view))
6289     {
6290       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
6291       if (headers_visible)
6292         {
6293           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
6294
6295           if (GTK_WIDGET_MAPPED (tree_view))
6296             gtk_tree_view_map_buttons (tree_view);
6297         }
6298       else
6299         {
6300           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
6301
6302           for (list = tree_view->priv->columns; list; list = list->next)
6303             {
6304               column = list->data;
6305               gtk_widget_unmap (column->button);
6306             }
6307           gdk_window_hide (tree_view->priv->header_window);
6308         }
6309     }
6310
6311   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
6312   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
6313   tree_view->priv->vadjustment->lower = 0;
6314   tree_view->priv->vadjustment->upper = tree_view->priv->height;
6315   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
6316
6317   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6318
6319   g_object_notify (G_OBJECT (tree_view), "headers_visible");
6320 }
6321
6322
6323 /**
6324  * gtk_tree_view_columns_autosize:
6325  * @tree_view: A #GtkTreeView.
6326  *
6327  * Resizes all columns to their optimal width.
6328  **/
6329 void
6330 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
6331 {
6332   gboolean dirty = FALSE;
6333   GList *list;
6334   GtkTreeViewColumn *column;
6335
6336   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6337
6338   for (list = tree_view->priv->columns; list; list = list->next)
6339     {
6340       column = list->data;
6341       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
6342         continue;
6343       column->dirty = TRUE;
6344       dirty = TRUE;
6345     }
6346
6347   if (dirty)
6348     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6349 }
6350
6351 /**
6352  * gtk_tree_view_set_headers_clickable:
6353  * @tree_view: A #GtkTreeView.
6354  * @setting: TRUE if the columns are clickable.
6355  *
6356  * Allow the column title buttons to be clicked.
6357  **/
6358 void
6359 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
6360                                      gboolean   setting)
6361 {
6362   GList *list;
6363
6364   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6365   g_return_if_fail (tree_view->priv->model != NULL);
6366
6367   for (list = tree_view->priv->columns; list; list = list->next)
6368     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
6369
6370   g_object_notify (G_OBJECT (tree_view), "headers_clickable");
6371 }
6372
6373
6374 /**
6375  * gtk_tree_view_set_rules_hint
6376  * @tree_view: a #GtkTreeView
6377  * @setting: %TRUE if the tree requires reading across rows
6378  *
6379  * This function tells GTK+ that the user interface for your
6380  * application requires users to read across tree rows and associate
6381  * cells with one another. By default, GTK+ will then render the tree
6382  * with alternating row colors. <emphasis>DO NOT</emphasis> use it
6383  * just because you prefer the appearance of the ruled tree; that's a
6384  * question for the theme. Some themes will draw tree rows in
6385  * alternating colors even when rules are turned off, and users who
6386  * prefer that appearance all the time can choose those themes. You
6387  * should call this function only as a <emphasis>semantic</emphasis>
6388  * hint to the theme engine that your tree makes alternating colors
6389  * useful from a functional standpoint (since it has lots of columns,
6390  * generally).
6391  *
6392  **/
6393 void
6394 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
6395                               gboolean      setting)
6396 {
6397   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6398
6399   setting = setting != FALSE;
6400
6401   if (tree_view->priv->has_rules != setting)
6402     {
6403       tree_view->priv->has_rules = setting;
6404       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6405     }
6406
6407   g_object_notify (G_OBJECT (tree_view), "rules_hint");
6408 }
6409
6410 /**
6411  * gtk_tree_view_get_rules_hint
6412  * @tree_view: a #GtkTreeView
6413  *
6414  * Gets the setting set by gtk_tree_view_set_rules_hint().
6415  *
6416  * Return value: %TRUE if rules are useful for the user of this tree
6417  **/
6418 gboolean
6419 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
6420 {
6421   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
6422
6423   return tree_view->priv->has_rules;
6424 }
6425
6426 /* Public Column functions
6427  */
6428
6429 /**
6430  * gtk_tree_view_append_column:
6431  * @tree_view: A #GtkTreeView.
6432  * @column: The #GtkTreeViewColumn to add.
6433  *
6434  * Appends @column to the list of columns.
6435  *
6436  * Return value: The number of columns in @tree_view after appending.
6437  **/
6438 gint
6439 gtk_tree_view_append_column (GtkTreeView       *tree_view,
6440                              GtkTreeViewColumn *column)
6441 {
6442   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6443   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6444   g_return_val_if_fail (column->tree_view == NULL, -1);
6445
6446   return gtk_tree_view_insert_column (tree_view, column, -1);
6447 }
6448
6449
6450 /**
6451  * gtk_tree_view_remove_column:
6452  * @tree_view: A #GtkTreeView.
6453  * @column: The #GtkTreeViewColumn to remove.
6454  *
6455  * Removes @column from @tree_view.
6456  *
6457  * Return value: The number of columns in @tree_view after removing.
6458  **/
6459 gint
6460 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
6461                              GtkTreeViewColumn *column)
6462 {
6463   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6464   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6465   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
6466
6467   _gtk_tree_view_column_unset_tree_view (column);
6468
6469   if (tree_view->priv->focus_column == column)
6470     tree_view->priv->focus_column = NULL;
6471
6472   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
6473
6474   tree_view->priv->n_columns--;
6475
6476   if (GTK_WIDGET_REALIZED (tree_view))
6477     {
6478       GList *list;
6479
6480       _gtk_tree_view_column_unrealize_button (column);
6481       for (list = tree_view->priv->columns; list; list = list->next)
6482         {
6483           column = GTK_TREE_VIEW_COLUMN (list->data);
6484           if (column->visible)
6485             column->dirty = TRUE;
6486         }
6487
6488       if (tree_view->priv->n_columns == 0 &&
6489           gtk_tree_view_get_headers_visible (tree_view))
6490         gdk_window_hide (tree_view->priv->header_window);
6491
6492       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6493     }
6494
6495   g_object_unref (G_OBJECT (column));
6496   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6497
6498   return tree_view->priv->n_columns;
6499 }
6500
6501 /**
6502  * gtk_tree_view_insert_column:
6503  * @tree_view: A #GtkTreeView.
6504  * @column: The #GtkTreeViewColumn to be inserted.
6505  * @position: The position to insert @column in.
6506  *
6507  * This inserts the @column into the @tree_view at @position.  If @position is
6508  * -1, then the column is inserted at the end.
6509  *
6510  * Return value: The number of columns in @tree_view after insertion.
6511  **/
6512 gint
6513 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
6514                              GtkTreeViewColumn *column,
6515                              gint               position)
6516 {
6517   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6518   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
6519   g_return_val_if_fail (column->tree_view == NULL, -1);
6520
6521   g_object_ref (G_OBJECT (column));
6522
6523   if (tree_view->priv->n_columns == 0 &&
6524       GTK_WIDGET_REALIZED (tree_view) &&
6525       gtk_tree_view_get_headers_visible (tree_view))
6526     {
6527       gdk_window_show (tree_view->priv->header_window);
6528     }
6529
6530   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
6531                                             column, position);
6532   tree_view->priv->n_columns++;
6533
6534   _gtk_tree_view_column_set_tree_view (column, tree_view);
6535
6536   if (GTK_WIDGET_REALIZED (tree_view))
6537     {
6538       GList *list;
6539
6540       _gtk_tree_view_column_realize_button (column);
6541
6542       for (list = tree_view->priv->columns; list; list = list->next)
6543         {
6544           column = GTK_TREE_VIEW_COLUMN (list->data);
6545           if (column->visible)
6546             column->dirty = TRUE;
6547         }
6548       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6549     }
6550
6551   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6552
6553   return tree_view->priv->n_columns;
6554 }
6555
6556 /**
6557  * gtk_tree_view_insert_column_with_attributes:
6558  * @tree_view: A #GtkTreeView
6559  * @position: The position to insert the new column in.
6560  * @title: The title to set the header to.
6561  * @cell: The #GtkCellRenderer.
6562  * @Varargs: A NULL terminated list of attributes.
6563  *
6564  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
6565  * @position.  If @position is -1, then the newly created column is inserted at
6566  * the end.  The column is initialized with the attributes given.
6567  *
6568  * Return value: The number of columns in @tree_view after insertion.
6569  **/
6570 gint
6571 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
6572                                              gint             position,
6573                                              gchar           *title,
6574                                              GtkCellRenderer *cell,
6575                                              ...)
6576 {
6577   GtkTreeViewColumn *column;
6578   gchar *attribute;
6579   va_list args;
6580   gint column_id;
6581
6582   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6583
6584   column = gtk_tree_view_column_new ();
6585
6586   gtk_tree_view_column_set_title (column, title);
6587   gtk_tree_view_column_set_cell_renderer (column, cell);
6588
6589   va_start (args, cell);
6590
6591   attribute = va_arg (args, gchar *);
6592
6593   while (attribute != NULL)
6594     {
6595       column_id = va_arg (args, gint);
6596       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
6597       attribute = va_arg (args, gchar *);
6598     }
6599
6600   va_end (args);
6601
6602   gtk_tree_view_insert_column (tree_view, column, position);
6603   g_object_unref (column);
6604
6605   return tree_view->priv->n_columns;
6606 }
6607
6608 /**
6609  * gtk_tree_view_insert_column_with_data_func:
6610  * @tree_view: a #GtkTreeView
6611  * @position: Position to insert, -1 for append
6612  * @title: column title
6613  * @cell: cell renderer for column
6614  * @func: function to set attributes of cell renderer
6615  * @data: data for @func
6616  * @dnotify: destroy notifier for @data
6617  *
6618  * Convenience function that inserts a new column into the #GtkTreeView
6619  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
6620  * attributes (normally using data from the model). See also
6621  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_set_cell_renderer().
6622  *
6623  * Return value: number of columns in the tree view post-insert
6624  **/
6625 gint
6626 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
6627                                              gint                       position,
6628                                              gchar                     *title,
6629                                              GtkCellRenderer           *cell,
6630                                              GtkTreeCellDataFunc        func,
6631                                              gpointer                   data,
6632                                              GDestroyNotify             dnotify)
6633 {
6634   GtkTreeViewColumn *column;
6635
6636   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
6637
6638   column = gtk_tree_view_column_new ();
6639
6640   gtk_tree_view_column_set_title (column, title);
6641   gtk_tree_view_column_set_cell_renderer (column, cell);
6642   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
6643
6644   gtk_tree_view_insert_column (tree_view, column, position);
6645
6646   g_object_unref (column);
6647
6648   return tree_view->priv->n_columns;
6649 }
6650
6651 /**
6652  * gtk_tree_view_get_column:
6653  * @tree_view: A #GtkTreeView.
6654  * @n: The position of the column, counting from 0.
6655  *
6656  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
6657  *
6658  * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
6659  * range of columns.
6660  **/
6661 GtkTreeViewColumn *
6662 gtk_tree_view_get_column (GtkTreeView *tree_view,
6663                           gint         n)
6664 {
6665   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6666
6667   if (n < 0 || n >= tree_view->priv->n_columns)
6668     return NULL;
6669
6670   if (tree_view->priv->columns == NULL)
6671     return NULL;
6672
6673   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
6674 }
6675
6676 /**
6677  * gtk_tree_view_get_columns:
6678  * @tree_view: A #GtkTreeView
6679  *
6680  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
6681  * The returned list must be freed with g_list_free ().
6682  *
6683  * Return value: A list of #GtkTreeViewColumn s
6684  **/
6685 GList *
6686 gtk_tree_view_get_columns (GtkTreeView *tree_view)
6687 {
6688   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6689
6690   return g_list_copy (tree_view->priv->columns);
6691 }
6692
6693 /**
6694  * gtk_tree_view_move_column_after:
6695  * @tree_view: A #GtkTreeView
6696  * @column: The #GtkTreeViewColumn to be moved.
6697  * @base_column: The #GtkTreeViewColumn to be moved relative to.
6698  *
6699  * Moves @column to be after to @base_column.  If @base_column is NULL, then
6700  * @column is placed in the first position.
6701  **/
6702 void
6703 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
6704                                  GtkTreeViewColumn *column,
6705                                  GtkTreeViewColumn *base_column)
6706 {
6707   GList *column_list_el, *base_el = NULL;
6708
6709   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6710
6711   column_list_el = g_list_find (tree_view->priv->columns, column);
6712   g_return_if_fail (column_list_el != NULL);
6713
6714   if (base_column)
6715     {
6716       base_el = g_list_find (tree_view->priv->columns, base_column);
6717       g_return_if_fail (base_el != NULL);
6718     }
6719
6720   if (column_list_el->prev == base_el)
6721     return;
6722
6723   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
6724   if (base_el == NULL)
6725     {
6726       column_list_el->prev = NULL;
6727       column_list_el->next = tree_view->priv->columns;
6728       if (column_list_el->next)
6729         column_list_el->next->prev = column_list_el;
6730       tree_view->priv->columns = column_list_el;
6731     }
6732   else
6733     {
6734       column_list_el->prev = base_el;
6735       column_list_el->next = base_el->next;
6736       if (column_list_el->next)
6737         column_list_el->next->prev = column_list_el;
6738       base_el->next = column_list_el;
6739     }
6740
6741   if (GTK_WIDGET_REALIZED (tree_view))
6742     {
6743       //gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6744       _gtk_tree_view_update_size (tree_view);
6745       gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view));
6746     }
6747
6748   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
6749 }
6750
6751 /**
6752  * gtk_tree_view_set_expander_column:
6753  * @tree_view: A #GtkTreeView
6754  * @column: NULL, or the column to draw the expander arrow at.
6755  * 
6756  * Sets the column to draw the expander arrow at. It must be in @tree_view.  If
6757  * @column is %NULL, then the expander arrow is fixed at the first column.
6758  **/
6759 void
6760 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
6761                                    GtkTreeViewColumn *column)
6762 {
6763   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6764   if (column != NULL)
6765     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6766
6767   if (tree_view->priv->expander_column != column)
6768     {
6769       GList *list;
6770
6771       if (column)
6772         {
6773           /* Confirm that column is in tree_view */
6774           for (list = tree_view->priv->columns; list; list = list->next)
6775             if (list->data == column)
6776               break;
6777           g_return_if_fail (list != NULL);
6778         }
6779
6780       tree_view->priv->expander_column = column;
6781       g_object_notify (G_OBJECT (tree_view), "expander_column");
6782     }
6783 }
6784
6785 /**
6786  * gtk_tree_view_get_expander_column:
6787  * @tree_view: A #GtkTreeView
6788  *
6789  * Returns the column that is the current expander column.  This
6790  * column has the expander arrow drawn next to it.
6791  *
6792  * Return value: The expander column.
6793  **/
6794 GtkTreeViewColumn *
6795 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
6796 {
6797   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
6798
6799   return tree_view->priv->expander_column;
6800 }
6801
6802
6803 /**
6804  * gtk_tree_view_set_column_drag_function:
6805  * @tree_view: A #GtkTreeView.
6806  * @func: A function to determine which columns are reorderable, or NULL.
6807  * @user_data: User data to be passed to @func, or NULL
6808  * @destroy: Destroy notifier for @user_data, or NULL
6809  *
6810  * Sets a user function for determining where a column may be dropped when
6811  * dragged.  This function is called on every column pair in turn at the
6812  * beginning of a column drag to determine where a drop can take place.  The
6813  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
6814  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
6815  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
6816  * are NULL, then they indicate an edge.  If @func is set to be NULL, then
6817  * @tree_view reverts to the default behavior of allowing all columns to be
6818  * dropped everywhere.
6819  **/
6820 void
6821 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
6822                                         GtkTreeViewColumnDropFunc  func,
6823                                         gpointer                   user_data,
6824                                         GtkDestroyNotify           destroy)
6825 {
6826   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6827
6828   if (tree_view->priv->column_drop_func_data_destroy)
6829     (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
6830
6831   tree_view->priv->column_drop_func = func;
6832   tree_view->priv->column_drop_func_data = user_data;
6833   tree_view->priv->column_drop_func_data_destroy = destroy;
6834 }
6835
6836 /**
6837  * gtk_tree_view_scroll_to_point:
6838  * @tree_view: a #GtkTreeView
6839  * @tree_x: X coordinate of new top-left pixel of visible area
6840  * @tree_y: Y coordinate of new top-left pixel of visible area
6841  *
6842  * Scrolls the tree view such that the top-left corner of the visible
6843  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
6844  * in tree window coordinates.  The @tree_view must be realized before
6845  * this function is called.  If it isn't, you probably want ot be
6846  * using gtk_tree_view_scroll_to_cell.
6847  **/
6848 void
6849 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
6850                                gint         tree_x,
6851                                gint         tree_y)
6852 {
6853   GtkAdjustment *hadj;
6854   GtkAdjustment *vadj;
6855
6856   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6857   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
6858
6859   hadj = tree_view->priv->hadjustment;
6860   vadj = tree_view->priv->vadjustment;
6861
6862   gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
6863   gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
6864 }
6865
6866 /**
6867  * gtk_tree_view_scroll_to_cell
6868  * @tree_view: A #GtkTreeView.
6869  * @path: The path of the row to move to.
6870  * @column: The #GtkTreeViewColumn to move horizontally to.
6871  * @row_align: The vertical alignment of the row specified by @path.
6872  * @col_align: The horizontal alignment of the column specified by @column.
6873  *
6874  * Moves the alignments of @tree_view to the position specified by
6875  * @column and @path.  If @column is NULL, then no horizontal
6876  * scrolling occurs.  Likewise, if @path is NULL no vertical scrolling
6877  * occurs.  @row_align determines where the row is placed, and
6878  * @col_align determines where @column is placed.  Both are expected
6879  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
6880  * right/bottom alignment, 0.5 means center.
6881  **/
6882 void
6883 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
6884                               GtkTreePath       *path,
6885                               GtkTreeViewColumn *column,
6886                               gfloat             row_align,
6887                               gfloat             col_align)
6888 {
6889   GdkRectangle cell_rect;
6890   GdkRectangle vis_rect;
6891   gint dest_x, dest_y;
6892
6893   /* FIXME work on unmapped/unrealized trees? maybe implement when
6894    * we do incremental reflow for trees
6895    */
6896
6897   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6898   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
6899   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
6900   g_return_if_fail (path != NULL || column != NULL);
6901
6902   row_align = CLAMP (row_align, 0.0, 1.0);
6903   col_align = CLAMP (col_align, 0.0, 1.0);
6904
6905   if (! GTK_WIDGET_REALIZED (tree_view))
6906     {
6907       if (path)
6908         tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
6909       if (column)
6910         tree_view->priv->scroll_to_column = column;
6911       tree_view->priv->scroll_to_row_align = row_align;
6912       tree_view->priv->scroll_to_col_align = col_align;
6913
6914       return;
6915     }
6916
6917   gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
6918   gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
6919
6920   dest_x = vis_rect.x;
6921   dest_y = vis_rect.y;
6922
6923   if (path)
6924     {
6925       dest_x = cell_rect.x +
6926         cell_rect.width * row_align -
6927         vis_rect.width * row_align;
6928     }
6929
6930   if (column)
6931     {
6932       dest_y = cell_rect.y +
6933         cell_rect.height * col_align -
6934         vis_rect.height * col_align;
6935     }
6936
6937   gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
6938 }
6939
6940
6941 /**
6942  * gtk_tree_view_row_activated:
6943  * @tree_view: A #GtkTreeView
6944  * @path: The #GtkTreePath to be activated.
6945  * @column: The #GtkTreeViewColumn to be activated.
6946  *
6947  * Activates the cell determined by @path and @column.
6948  **/
6949 void
6950 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
6951                              GtkTreePath       *path,
6952                              GtkTreeViewColumn *column)
6953 {
6954   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6955
6956   /* FIXME: Actually activate the path internally, not just emit the signal */
6957   /*  g_warning ("FIXME: Actually activate the path internally, not just emit the signal\n"); */
6958   g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
6959 }
6960
6961
6962 static void
6963 gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
6964                                  GtkRBNode  *node,
6965                                  gpointer  data)
6966 {
6967   GtkTreeView *tree_view = data;
6968
6969   if (node->children)
6970     _gtk_rbtree_traverse (node->children,
6971                           node->children->root,
6972                           G_PRE_ORDER,
6973                           gtk_tree_view_expand_all_helper,
6974                           data);
6975   else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
6976     {
6977       GtkTreePath *path;
6978       GtkTreeIter iter;
6979       GtkTreeIter child;
6980
6981       node->children = _gtk_rbtree_new ();
6982       node->children->parent_tree = tree;
6983       node->children->parent_node = node;
6984       path = _gtk_tree_view_find_path (tree_view, tree, node);
6985       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6986       gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
6987       gtk_tree_view_build_tree (tree_view,
6988                                 node->children,
6989                                 &child,
6990                                 gtk_tree_path_get_depth (path) + 1,
6991                                 TRUE,
6992                                 GTK_WIDGET_REALIZED (tree_view));
6993       gtk_tree_path_free (path);
6994     }
6995 }
6996
6997 /**
6998  * gtk_tree_view_expand_all:
6999  * @tree_view: A #GtkTreeView.
7000  *
7001  * Recursively expands all nodes in the @tree_view.
7002  **/
7003 void
7004 gtk_tree_view_expand_all (GtkTreeView *tree_view)
7005 {
7006   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7007   g_return_if_fail (tree_view->priv->tree != NULL);
7008
7009   _gtk_rbtree_traverse (tree_view->priv->tree,
7010                         tree_view->priv->tree->root,
7011                         G_PRE_ORDER,
7012                         gtk_tree_view_expand_all_helper,
7013                         tree_view);
7014
7015   _gtk_tree_view_update_size (tree_view);
7016 }
7017
7018 static void
7019 gtk_tree_view_collapse_all_helper (GtkRBTree  *tree,
7020                                    GtkRBNode  *node,
7021                                    gpointer    data)
7022 {
7023   if (node->children)
7024     {
7025       GtkTreePath *path;
7026       GtkTreeIter iter;
7027
7028       path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
7029                                        node->children,
7030                                        node->children->root);
7031       gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
7032                                &iter,
7033                                path);
7034       gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
7035                                     node->children,
7036                                     &iter,
7037                                     gtk_tree_path_get_depth (path));
7038
7039       /* Ensure we don't have a dangling pointer to a dead node */
7040       ensure_unprelighted (GTK_TREE_VIEW (data));
7041
7042       _gtk_rbtree_remove (node->children);
7043       gtk_tree_path_free (path);
7044     }
7045 }
7046
7047 /**
7048  * gtk_tree_view_collapse_all:
7049  * @tree_view: A #GtkTreeView.
7050  *
7051  * Recursively collapses all visible, expanded nodes in @tree_view.
7052  **/
7053 void
7054 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
7055 {
7056   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7057   g_return_if_fail (tree_view->priv->tree != NULL);
7058
7059   _gtk_rbtree_traverse (tree_view->priv->tree,
7060                         tree_view->priv->tree->root,
7061                         G_PRE_ORDER,
7062                         gtk_tree_view_collapse_all_helper,
7063                         tree_view);
7064
7065   if (GTK_WIDGET_MAPPED (tree_view))
7066     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7067 }
7068
7069 /* FIXME the bool return values for expand_row and collapse_row are
7070  * not analagous; they should be TRUE if the row had children and
7071  * was not already in the requested state.
7072  */
7073
7074
7075 static gboolean
7076 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
7077                                GtkTreePath *path,
7078                                GtkRBTree   *tree,
7079                                GtkRBNode   *node,
7080                                gboolean     open_all)
7081 {
7082   GtkTreeIter iter;
7083   GtkTreeIter temp;
7084   gboolean expand;
7085
7086   if (node->children)
7087     return TRUE;
7088
7089   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7090   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
7091     return FALSE;
7092
7093   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
7094
7095   if (expand)
7096     return FALSE;
7097
7098   node->children = _gtk_rbtree_new ();
7099   node->children->parent_tree = tree;
7100   node->children->parent_node = node;
7101
7102   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
7103
7104   gtk_tree_view_build_tree (tree_view,
7105                             node->children,
7106                             &temp,
7107                             gtk_tree_path_get_depth (path) + 1,
7108                             open_all,
7109                             GTK_WIDGET_REALIZED (tree_view));
7110
7111   if (GTK_WIDGET_MAPPED (tree_view))
7112     {
7113       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7114       _gtk_tree_view_update_size (tree_view);
7115     }
7116
7117   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
7118
7119   return TRUE;
7120 }
7121
7122
7123 /**
7124  * gtk_tree_view_expand_row:
7125  * @tree_view: a #GtkTreeView
7126  * @path: path to a row
7127  * @open_all: whether to recursively expand, or just expand immediate children
7128  *
7129  * Opens the row so its children are visible
7130  *
7131  * Return value: %TRUE if the row existed and had children
7132  **/
7133 gboolean
7134 gtk_tree_view_expand_row (GtkTreeView *tree_view,
7135                           GtkTreePath *path,
7136                           gboolean     open_all)
7137 {
7138   GtkRBTree *tree;
7139   GtkRBNode *node;
7140
7141   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7142   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
7143   g_return_val_if_fail (path != NULL, FALSE);
7144
7145   if (_gtk_tree_view_find_node (tree_view,
7146                                 path,
7147                                 &tree,
7148                                 &node))
7149     return FALSE;
7150
7151   return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all);
7152 }
7153
7154 static gboolean
7155 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
7156                                  GtkTreePath *path,
7157                                  GtkRBTree   *tree,
7158                                  GtkRBNode   *node)
7159 {
7160   GtkTreeIter iter;
7161   GtkTreeIter children;
7162   gboolean collapse;
7163
7164   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
7165
7166   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
7167
7168   if (collapse)
7169     return FALSE;
7170
7171   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
7172
7173   gtk_tree_view_discover_dirty (tree_view,
7174                                 node->children,
7175                                 &children,
7176                                 gtk_tree_path_get_depth (path));
7177
7178   /* Ensure we don't have a dangling pointer to a dead node */
7179   ensure_unprelighted (tree_view);
7180
7181   if (tree_view->priv->destroy_count_func)
7182     {
7183       gint child_count = 0;
7184       if (node->children)
7185         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
7186       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
7187     }
7188
7189   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
7190     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0);
7191   _gtk_rbtree_remove (node->children);
7192
7193   if (GTK_WIDGET_MAPPED (tree_view))
7194     {
7195       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7196       _gtk_tree_view_update_size (tree_view);
7197     }
7198
7199   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7200     {
7201       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7202
7203       if (gtk_tree_path_is_ancestor (path, cursor_path))
7204         {
7205           gtk_tree_row_reference_free (tree_view->priv->cursor);
7206           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7207                                                                       tree_view->priv->model,
7208                                                                       path);
7209         }
7210       gtk_tree_path_free (cursor_path);
7211     }
7212
7213   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
7214       {
7215       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
7216       if (gtk_tree_path_is_ancestor (path, anchor_path))
7217         {
7218           gtk_tree_row_reference_free (tree_view->priv->anchor);
7219           tree_view->priv->anchor = NULL;
7220         }
7221       gtk_tree_path_free (anchor_path);
7222
7223     }
7224
7225   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
7226
7227   return TRUE;
7228 }
7229
7230 /**
7231  * gtk_tree_view_collapse_row:
7232  * @tree_view: a #GtkTreeView
7233  * @path: path to a row in the @tree_view
7234  *
7235  * Collapses a row (hides its child rows, if they exist.)
7236  *
7237  * Return value: %TRUE if the row was collapsed.
7238  **/
7239 gboolean
7240 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
7241                             GtkTreePath *path)
7242 {
7243   GtkRBTree *tree;
7244   GtkRBNode *node;
7245
7246   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7247   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7248   g_return_val_if_fail (path != NULL, FALSE);
7249
7250   if (_gtk_tree_view_find_node (tree_view,
7251                                 path,
7252                                 &tree,
7253                                 &node))
7254     return FALSE;
7255
7256   if (node->children == NULL)
7257     return FALSE;
7258
7259   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node);
7260 }
7261
7262 static void
7263 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
7264                                         GtkRBTree              *tree,
7265                                         GtkTreePath            *path,
7266                                         GtkTreeViewMappingFunc  func,
7267                                         gpointer                user_data)
7268 {
7269   GtkRBNode *node;
7270   gint *indices;
7271   gint depth;
7272   gint i = 0;
7273
7274   if (tree == NULL || tree->root == NULL)
7275     return;
7276
7277   node = tree->root;
7278
7279   indices = gtk_tree_path_get_indices (path);
7280   depth = gtk_tree_path_get_depth (path);
7281
7282   while (node && node->left != tree->nil)
7283     node = node->left;
7284
7285   while (node)
7286     {
7287       if (node->children)
7288         {
7289           gtk_tree_path_append_index (path, 0);
7290           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
7291           gtk_tree_path_up (path);
7292           (* func) (tree_view, path, user_data);
7293         }
7294       i++;
7295       indices[depth -1] = i;
7296       node = _gtk_rbtree_next (tree, node);
7297     }
7298 }
7299
7300 /**
7301  * gtk_tree_view_map_expanded_rows:
7302  * @tree_view: A #GtkTreeView
7303  * @func: A function to be called
7304  * @data: User data to be passed to the function.
7305  *
7306  * Calls @func on all expanded rows.
7307  **/
7308 void
7309 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
7310                                  GtkTreeViewMappingFunc  func,
7311                                  gpointer                user_data)
7312 {
7313   GtkTreePath *path;
7314
7315   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7316   g_return_if_fail (func != NULL);
7317
7318   path = gtk_tree_path_new_root ();
7319
7320   gtk_tree_view_map_expanded_rows_helper (tree_view,
7321                                           tree_view->priv->tree,
7322                                           path, func, user_data);
7323
7324   gtk_tree_path_free (path);
7325 }
7326
7327 /**
7328  * gtk_tree_view_row_expanded:
7329  * @tree_view: A #GtkTreeView.
7330  * @path: A #GtkTreePath to test expansion state.
7331  * 
7332  * Returns TRUE if the node pointed to by @path is expanded in @tree_view.
7333  * 
7334  * Return value: TRUE if #path is expanded.
7335  **/
7336 gboolean
7337 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
7338                             GtkTreePath *path)
7339 {
7340   GtkRBTree *tree;
7341   GtkRBNode *node;
7342
7343   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7344   g_return_val_if_fail (path != NULL, FALSE);
7345
7346   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7347
7348   if (node == NULL)
7349     return FALSE;
7350
7351   return (node->children != NULL);
7352 }
7353
7354 static GtkTargetEntry row_targets[] = {
7355   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7356 };
7357
7358
7359 /**
7360  * gtk_tree_view_get_reorderable:
7361  * @tree_view: a #GtkTreeView
7362  *
7363  * Retrieves whether the user can reorder the tree via drag-and-drop. See
7364  * gtk_tree_view_set_reorderable().
7365  *
7366  * Return value: %TRUE if the tree can be reordered.
7367  **/
7368 gboolean
7369 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
7370 {
7371   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7372
7373   return tree_view->priv->reorderable;
7374 }
7375
7376 /**
7377  * gtk_tree_view_set_reorderable:
7378  * @tree_view: A #GtkTreeView.
7379  * @reorderable: TRUE, if the tree can be reordered.
7380  *
7381  * This function is a convenience function to allow you to reorder models that
7382  * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
7383  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is TRUE, then
7384  * the user can reorder the model by dragging and dropping columns.  The
7385  * developer will can listen to these changes by connecting to the model's
7386  * signals.
7387  *
7388  * This function does not give you any degree of control over the order -- any
7389  * reorderering is allowed.  If more control is needed, you should probably
7390  * handle drag and drop manually.
7391  **/
7392 void
7393 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
7394                                gboolean     reorderable)
7395 {
7396   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7397
7398   if (tree_view->priv->reorderable == (reorderable?TRUE:FALSE))
7399     return;
7400
7401   gtk_tree_view_set_rows_drag_source (tree_view,
7402                                       GDK_BUTTON1_MASK,
7403                                       row_targets,
7404                                       G_N_ELEMENTS (row_targets),
7405                                       GDK_ACTION_MOVE,
7406                                       NULL, NULL);
7407   gtk_tree_view_set_rows_drag_dest (tree_view,
7408                                     row_targets,
7409                                     G_N_ELEMENTS (row_targets),
7410                                     GDK_ACTION_MOVE,
7411                                     NULL, NULL);
7412
7413   g_object_notify (G_OBJECT (tree_view), "reorderable");
7414 }
7415
7416 static void
7417 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
7418                                GtkTreePath     *path,
7419                                gboolean         clear_and_select)
7420 {
7421   GtkRBTree *tree = NULL;
7422   GtkRBNode *node = NULL;
7423
7424   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7425     {
7426       GtkTreePath *cursor_path;
7427       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7428       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7429       gtk_tree_path_free (cursor_path);
7430     }
7431   gtk_tree_row_reference_free (tree_view->priv->cursor);
7432
7433   tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
7434                                                               tree_view->priv->model,
7435                                                               path);
7436   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7437   if (tree == NULL)
7438     return;
7439
7440   if (clear_and_select && !tree_view->priv->in_free_motion)
7441     _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7442                                               node, tree, path,
7443                                               tree_view->priv->in_extended_selection?GDK_SHIFT_MASK:0);
7444   gtk_tree_view_clamp_node_visible (tree_view, tree, node);
7445   gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
7446 }
7447
7448 /**
7449  * gtk_tree_view_set_cursor:
7450  * @tree_view: A #GtkTreeView
7451  * @path: A #GtkTreePath
7452  *
7453  * Sets the current keyboard focus to be at @path, and selects it.  This is
7454  * useful when you want to focus the user's attention on a particular row.  If
7455  * you want to give the user keyboard focus in the tree_view, you should use
7456  * this function to set the correct path, and gtk_widget_grab_focus (GTK_WIDGET
7457  * (tree_view)) to actually give focus to the @tree_view.
7458  **/
7459 void
7460 gtk_tree_view_set_cursor (GtkTreeView *tree_view,
7461                           GtkTreePath *path)
7462 {
7463   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7464   g_return_if_fail (path != NULL);
7465
7466   gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
7467 }
7468
7469
7470 /**
7471  * gtk_tree_view_get_path_at_pos:
7472  * @tree_view: A #GtkTreeView.
7473  * @window: The #GdkWindow to check against.
7474  * @x: The x position to be identified.
7475  * @y: The y position to be identified.
7476  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
7477  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
7478  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
7479  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
7480  *
7481  * Finds the path at the point (@x, @y) relative to @window.  If @window is
7482  * NULL, then the point is found relative to the widget coordinates.  This
7483  * function is expected to be called after an event, with event->window being
7484  * passed in as @window.  It is primarily for things like popup menus.  If @path
7485  * is non-NULL, then it will be filled with the #GtkTreePath at that point.
7486  * This path should be freed with #gtk_tree_path_free.  If @column is non-NULL,
7487  * then it will be filled with the column at that point. @cell_x and @cell_y
7488  * return the coordinates relative to the cell background (i.e. the
7489  * background_area passed to gtk_cell_renderer_render()).  This function only
7490  * works if @tree_view is realized.
7491  *
7492  * Return value: TRUE if a row exists at that coordinate.
7493  **/
7494 gboolean
7495 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
7496                                GdkWindow          *window,
7497                                gint                x,
7498                                gint                y,
7499                                GtkTreePath       **path,
7500                                GtkTreeViewColumn **column,
7501                                gint               *cell_x,
7502                                gint               *cell_y)
7503 {
7504   GtkRBTree *tree;
7505   GtkRBNode *node;
7506   gint y_offset;
7507
7508   g_return_val_if_fail (tree_view != NULL, FALSE);
7509   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
7510   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
7511
7512   if (window)
7513     g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
7514
7515   if (path)
7516     *path = NULL;
7517   if (column)
7518     *column = NULL;
7519
7520   if (x > tree_view->priv->hadjustment->upper)
7521     return FALSE;
7522
7523   if (x < 0 || y < 0)
7524     return FALSE;
7525
7526   if (column || cell_x)
7527     {
7528       GtkTreeViewColumn *tmp_column;
7529       GtkTreeViewColumn *last_column = NULL;
7530       GList *list;
7531       gint remaining_x = x;
7532       gboolean found = FALSE;
7533
7534       for (list = tree_view->priv->columns; list; list = list->next)
7535         {
7536           tmp_column = list->data;
7537
7538           if (tmp_column->visible == FALSE)
7539             continue;
7540
7541           last_column = tmp_column;
7542           if (remaining_x <= tmp_column->width)
7543             {
7544               found = TRUE;
7545
7546               if (column)
7547                 *column = tmp_column;
7548
7549               if (cell_x)
7550                 *cell_x = remaining_x;
7551
7552               break;
7553             }
7554           remaining_x -= tmp_column->width;
7555         }
7556
7557       if (!found)
7558         {
7559           if (column)
7560             *column = last_column;
7561
7562           if (cell_x)
7563             *cell_x = last_column->width + remaining_x;
7564         }
7565     }
7566
7567   if (window)
7568     {
7569       y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7570                                           TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
7571                                           &tree, &node);
7572     }
7573   else
7574     {
7575       if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
7576         return FALSE;
7577
7578       y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7579                                           TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
7580                                           &tree, &node);
7581     }
7582
7583   if (tree == NULL)
7584     return FALSE;
7585
7586   if (cell_y)
7587     *cell_y = y_offset;
7588
7589   if (path)
7590     *path = _gtk_tree_view_find_path (tree_view, tree, node);
7591
7592   return TRUE;
7593 }
7594
7595
7596 /**
7597  * gtk_tree_view_get_cell_area:
7598  * @tree_view: a #GtkTreeView
7599  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7600  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7601  * @rect: rectangle to fill with cell rect
7602  *
7603  * Fills the bounding rectangle in tree window coordinates for the cell at the
7604  * row specified by @path and the column specified by @column.  If @path is
7605  * %NULL, the y and height fields of the rectangle will be filled with 0. If
7606  * @column is %NULL, the x and width fields will be filled with 0.  The sum of
7607  * all cell rects does not cover the entire tree; there are extra pixels in
7608  * between rows, for example. The returned rectangle is equivalent to the
7609  * @cell_area passed to gtk_cell_renderer_render().  This function is only valid
7610  * if #tree_view is realized.
7611  **/
7612 void
7613 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
7614                              GtkTreePath        *path,
7615                              GtkTreeViewColumn  *column,
7616                              GdkRectangle       *rect)
7617 {
7618   GtkRBTree *tree = NULL;
7619   GtkRBNode *node = NULL;
7620   gint vertical_separator;
7621
7622   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7623   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7624   g_return_if_fail (rect != NULL);
7625
7626   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
7627
7628   rect->x = 0;
7629   rect->y = 0;
7630   rect->width = 0;
7631   rect->height = 0;
7632
7633   if (path)
7634     {
7635       /* Get vertical coords */
7636
7637       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7638
7639       if (tree == NULL)
7640         {
7641           g_warning (G_STRLOC": no row corresponding to path");
7642           return;
7643         }
7644
7645       /* Remember that the rbtree stores node height including the vertical
7646        * separator, see comment at top of file.
7647        */
7648       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
7649
7650       rect->height = CELL_HEIGHT (node, vertical_separator);
7651     }
7652
7653   if (column)
7654     {
7655       gint x2 = 0;
7656
7657       gtk_tree_view_get_cell_xrange (tree_view, tree, column, &rect->x, &x2);
7658       rect->width = x2 - rect->x;
7659     }
7660 }
7661
7662 /**
7663  * gtk_tree_view_get_background_area:
7664  * @tree_view: a #GtkTreeView
7665  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
7666  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
7667  * @rect: rectangle to fill with cell background rect
7668  *
7669  * Fills the bounding rectangle in tree window coordinates for the
7670  * cell at the row specified by @path and the column specified by
7671  * @column.  If @path is %NULL, the y and height fields of the
7672  * rectangle will be filled with 0. If @column is %NULL, the x and
7673  * width fields will be filled with 0.  The returned rectangle is
7674  * equivalent to the @background_area passed to
7675  * gtk_cell_renderer_render().  These background areas tile to cover
7676  * the entire tree window (except for the area used for header
7677  * buttons). Contrast with the cell_area, returned by
7678  * gtk_tree_view_get_cell_area(), which returns only the cell itself,
7679  * excluding surrounding borders and the tree expander area.
7680  *
7681  **/
7682 void
7683 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
7684                                    GtkTreePath        *path,
7685                                    GtkTreeViewColumn  *column,
7686                                    GdkRectangle       *rect)
7687 {
7688   GtkRBTree *tree = NULL;
7689   GtkRBNode *node = NULL;
7690
7691   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7692   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
7693   g_return_if_fail (rect != NULL);
7694
7695   rect->x = 0;
7696   rect->y = 0;
7697   rect->width = 0;
7698   rect->height = 0;
7699
7700   if (path)
7701     {
7702       /* Get vertical coords */
7703
7704       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7705
7706       if (tree == NULL)
7707         {
7708           g_warning (G_STRLOC": no row corresponding to path");
7709           return;
7710         }
7711
7712       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
7713
7714       rect->height = BACKGROUND_HEIGHT (node);
7715     }
7716
7717   if (column)
7718     {
7719       gint x2 = 0;
7720
7721       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
7722       rect->width = x2 - rect->x;
7723     }
7724 }
7725
7726 /**
7727  * gtk_tree_view_get_visible_rect:
7728  * @tree_view: a #GtkTreeView
7729  * @visible_rect: rectangle to fill
7730  *
7731  * Fills @visible_rect with the currently-visible region of the
7732  * buffer, in tree coordinates. Convert to widget coordinates with
7733  * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
7734  * 0,0 for row 0 of the tree, and cover the entire scrollable area of
7735  * the tree.
7736  **/
7737 void
7738 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
7739                                 GdkRectangle *visible_rect)
7740 {
7741   GtkWidget *widget;
7742
7743   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7744
7745   widget = GTK_WIDGET (tree_view);
7746
7747   if (visible_rect)
7748     {
7749       visible_rect->x = tree_view->priv->hadjustment->value;
7750       visible_rect->y = tree_view->priv->vadjustment->value;
7751       visible_rect->width = widget->allocation.width;
7752       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7753     }
7754 }
7755
7756 /**
7757  * gtk_tree_view_widget_to_tree_coords:
7758  * @tree_view: a #GtkTreeView
7759  * @wx: widget X coordinate
7760  * @wy: widget Y coordinate
7761  * @tx: return location for tree X coordinate
7762  * @ty: return location for tree Y coordinate
7763  *
7764  * Converts widget coordinates to coordinates for the
7765  * tree window (the full scrollable area of the tree).
7766  *
7767  **/
7768 void
7769 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
7770                                      gint         wx,
7771                                      gint         wy,
7772                                      gint        *tx,
7773                                      gint        *ty)
7774 {
7775   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7776
7777   if (tx)
7778     {
7779       *tx = wx + tree_view->priv->hadjustment->value;
7780     }
7781
7782   if (ty)
7783     {
7784       *ty = wy + tree_view->priv->vadjustment->value;
7785     }
7786 }
7787
7788 /**
7789  * gtk_tree_view_tree_to_widget_coords:
7790  * @tree_view: a #GtkTreeView
7791  * @tx: tree X coordinate
7792  * @ty: tree Y coordinate
7793  * @wx: return location for widget X coordinate
7794  * @wy: return location for widget Y coordinate
7795  *
7796  * Converts tree coordinates (coordinates in full scrollable area of the tree)
7797  * to widget coordinates.
7798  *
7799  **/
7800 void
7801 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
7802                                      gint         tx,
7803                                      gint         ty,
7804                                      gint        *wx,
7805                                      gint        *wy)
7806 {
7807   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7808
7809   if (wx)
7810     {
7811       *wx = tx - tree_view->priv->hadjustment->value;
7812     }
7813
7814   if (wy)
7815     {
7816       *wy = ty - tree_view->priv->vadjustment->value;
7817     }
7818 }
7819
7820
7821 void
7822 gtk_tree_view_set_rows_drag_source (GtkTreeView              *tree_view,
7823                                     GdkModifierType           start_button_mask,
7824                                     const GtkTargetEntry     *targets,
7825                                     gint                      n_targets,
7826                                     GdkDragAction             actions,
7827                                     GtkTreeViewDraggableFunc  row_draggable_func,
7828                                     gpointer                  user_data)
7829 {
7830   TreeViewDragInfo *di;
7831
7832   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7833
7834   di = ensure_info (tree_view);
7835   clear_source_info (di);
7836
7837   di->start_button_mask = start_button_mask;
7838   di->source_target_list = gtk_target_list_new (targets, n_targets);
7839   di->source_actions = actions;
7840
7841   if (row_draggable_func)
7842     {
7843       di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
7844                                                   user_data, NULL);
7845       g_closure_ref (di->row_draggable_closure);
7846       g_closure_sink (di->row_draggable_closure);
7847     }
7848
7849   di->source_set = TRUE;
7850 }
7851
7852 void
7853 gtk_tree_view_set_rows_drag_dest (GtkTreeView              *tree_view,
7854                                   const GtkTargetEntry     *targets,
7855                                   gint                      n_targets,
7856                                   GdkDragAction             actions,
7857                                   GtkTreeViewDroppableFunc  location_droppable_func,
7858                                   gpointer                  user_data)
7859 {
7860   TreeViewDragInfo *di;
7861
7862   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7863
7864   gtk_drag_dest_set (GTK_WIDGET (tree_view),
7865                      0,
7866                      NULL,
7867                      0,
7868                      actions);
7869
7870   di = ensure_info (tree_view);
7871   clear_dest_info (di);
7872
7873   if (targets)
7874     di->dest_target_list = gtk_target_list_new (targets, n_targets);
7875
7876   if (location_droppable_func)
7877     {
7878       di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
7879                                                        user_data, NULL);
7880       g_closure_ref (di->location_droppable_closure);
7881       g_closure_sink (di->location_droppable_closure);
7882     }
7883
7884   di->dest_set = TRUE;
7885 }
7886
7887 void
7888 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
7889 {
7890   TreeViewDragInfo *di;
7891
7892   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7893
7894   di = get_info (tree_view);
7895
7896   if (di)
7897     {
7898       if (di->source_set)
7899         {
7900           clear_source_info (di);
7901           di->source_set = FALSE;
7902         }
7903
7904       if (!di->dest_set && !di->source_set)
7905         remove_info (tree_view);
7906     }
7907 }
7908
7909 void
7910 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
7911 {
7912   TreeViewDragInfo *di;
7913
7914   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7915
7916   di = get_info (tree_view);
7917
7918   if (di)
7919     {
7920       if (di->dest_set)
7921         {
7922           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
7923           clear_dest_info (di);
7924           di->dest_set = FALSE;
7925         }
7926
7927       if (!di->dest_set && !di->source_set)
7928         remove_info (tree_view);
7929     }
7930 }
7931
7932 void
7933 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
7934                                  GtkTreePath            *path,
7935                                  GtkTreeViewDropPosition pos)
7936 {
7937   GtkTreePath *current_dest;
7938   /* Note; this function is exported to allow a custom DND
7939    * implementation, so it can't touch TreeViewDragInfo
7940    */
7941
7942   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7943
7944   current_dest = NULL;
7945
7946   if (tree_view->priv->drag_dest_row)
7947     current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7948
7949   if (current_dest)
7950     {
7951       gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
7952       gtk_tree_path_free (current_dest);
7953     }
7954
7955   if (tree_view->priv->drag_dest_row)
7956     gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
7957
7958   tree_view->priv->drag_dest_pos = pos;
7959
7960   if (path)
7961     {
7962       tree_view->priv->drag_dest_row =
7963         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
7964       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
7965     }
7966   else
7967     tree_view->priv->drag_dest_row = NULL;
7968 }
7969
7970 void
7971 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
7972                                  GtkTreePath             **path,
7973                                  GtkTreeViewDropPosition  *pos)
7974 {
7975   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7976
7977   if (path)
7978     {
7979       if (tree_view->priv->drag_dest_row)
7980         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
7981       else
7982         *path = NULL;
7983     }
7984
7985   if (pos)
7986     *pos = tree_view->priv->drag_dest_pos;
7987 }
7988
7989 gboolean
7990 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
7991                                    gint                     drag_x,
7992                                    gint                     drag_y,
7993                                    GtkTreePath            **path,
7994                                    GtkTreeViewDropPosition *pos)
7995 {
7996   gint cell_y;
7997   gdouble offset_into_row;
7998   gdouble quarter;
7999   gint x, y;
8000   GdkRectangle cell;
8001   GtkTreeViewColumn *column = NULL;
8002   GtkTreePath *tmp_path = NULL;
8003
8004   /* Note; this function is exported to allow a custom DND
8005    * implementation, so it can't touch TreeViewDragInfo
8006    */
8007
8008   g_return_val_if_fail (tree_view != NULL, FALSE);
8009   g_return_val_if_fail (drag_x >= 0, FALSE);
8010   g_return_val_if_fail (drag_y >= 0, FALSE);
8011   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
8012
8013
8014   if (path)
8015     *path = NULL;
8016
8017   if (tree_view->priv->tree == NULL)
8018     return FALSE;
8019
8020   /* remember that drag_x and drag_y are in widget coords, convert to tree window */
8021
8022   gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
8023                                        &x, &y);
8024
8025   /* If in the top quarter of a row, we drop before that row; if
8026    * in the bottom quarter, drop after that row; if in the middle,
8027    * and the row has children, drop into the row.
8028    */
8029
8030   if (!gtk_tree_view_get_path_at_pos (tree_view,
8031                                       tree_view->priv->bin_window,
8032                                       x, y,
8033                                       &tmp_path,
8034                                       &column,
8035                                       NULL,
8036                                       &cell_y))
8037     return FALSE;
8038
8039   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
8040                                      &cell);
8041
8042   offset_into_row = cell_y;
8043
8044   if (path)
8045     *path = tmp_path;
8046   else
8047     gtk_tree_path_free (tmp_path);
8048
8049   tmp_path = NULL;
8050
8051   quarter = cell.height / 4.0;
8052
8053   if (pos)
8054     {
8055       if (offset_into_row < quarter)
8056         {
8057           *pos = GTK_TREE_VIEW_DROP_BEFORE;
8058         }
8059       else if (offset_into_row < quarter * 2)
8060         {
8061           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
8062         }
8063       else if (offset_into_row < quarter * 3)
8064         {
8065           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
8066         }
8067       else
8068         {
8069           *pos = GTK_TREE_VIEW_DROP_AFTER;
8070         }
8071     }
8072
8073   return TRUE;
8074 }
8075
8076
8077
8078 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
8079 /**
8080  * gtk_tree_view_create_row_drag_icon:
8081  * @tree_view: a #GtkTreeView
8082  * @path: a #GtkTreePath in @tree_view
8083  *
8084  * Creates a GdkPixmap representation of the row at @path.  This image is used
8085  * for a drag icon.
8086  *
8087  * Return value: a newly allocatdd pixmap of the drag icon.
8088  **/
8089 GdkPixmap *
8090 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
8091                                     GtkTreePath  *path)
8092 {
8093   GtkTreeIter   iter;
8094   GtkRBTree    *tree;
8095   GtkRBNode    *node;
8096   gint cell_offset;
8097   GList *list;
8098   GdkRectangle background_area;
8099   GtkWidget *widget;
8100   gint depth;
8101   /* start drawing inside the black outline */
8102   gint x = 1, y = 1;
8103   GdkDrawable *drawable;
8104   gint bin_window_width;
8105
8106   widget = GTK_WIDGET (tree_view);
8107
8108   depth = gtk_tree_path_get_depth (path);
8109
8110   _gtk_tree_view_find_node (tree_view,
8111                             path,
8112                             &tree,
8113                             &node);
8114
8115   if (tree == NULL)
8116     return NULL;
8117
8118   if (!gtk_tree_model_get_iter (tree_view->priv->model,
8119                                 &iter,
8120                                 path))
8121     return NULL;
8122
8123   cell_offset = x;
8124
8125   background_area.y = y;
8126   background_area.height = BACKGROUND_HEIGHT (node);
8127
8128   gdk_drawable_get_size (tree_view->priv->bin_window,
8129                          &bin_window_width, NULL);
8130
8131   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
8132                              bin_window_width + 2,
8133                              background_area.height + 2,
8134                              -1);
8135
8136   gdk_draw_rectangle (drawable,
8137                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
8138                       TRUE,
8139                       0, 0,
8140                       bin_window_width + 2,
8141                       background_area.height + 2);
8142
8143   gdk_draw_rectangle (drawable,
8144                       widget->style->black_gc,
8145                       FALSE,
8146                       0, 0,
8147                       bin_window_width + 1,
8148                       background_area.height + 1);
8149
8150   for (list = tree_view->priv->columns; list; list = list->next)
8151     {
8152       GtkTreeViewColumn *column = list->data;
8153       GdkRectangle cell_area;
8154       gint vertical_separator;
8155
8156       if (!column->visible)
8157         continue;
8158
8159       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter);
8160
8161       background_area.x = cell_offset;
8162       background_area.width = column->displayed_width;
8163
8164       cell_area = background_area;
8165
8166       gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
8167       cell_area.y += vertical_separator / 2;
8168       cell_area.height -= vertical_separator;
8169
8170       if (gtk_tree_view_is_expander_column (tree_view, column) &&
8171           TREE_VIEW_DRAW_EXPANDERS(tree_view))
8172         {
8173           cell_area.x += depth * tree_view->priv->tab_offset;
8174           cell_area.width -= depth * tree_view->priv->tab_offset;
8175         }
8176
8177       if (gtk_tree_view_column_cell_is_visible (column))
8178         gtk_tree_view_column_cell_render (column,
8179                                           drawable,
8180                                           &background_area,
8181                                           &cell_area,
8182                                           NULL,
8183                                           0);
8184
8185       cell_offset += column->displayed_width;
8186     }
8187
8188   return drawable;
8189 }
8190
8191
8192 /**
8193  * gtk_tree_view_set_destroy_count_func:
8194  * @tree_view: A #GtkTreeView
8195  * @func: Function to be called when a view row is destroyed, or NULL
8196  * @data: User data to be passed to @func, or NULL
8197  * @destroy: Destroy notifier for @data, or NULL
8198  * 
8199  * This function should almost never be used.  It is meant for private use by
8200  * ATK for determining the number of visible children that are removed when the
8201  * user collapses a row, or a row is deleted.
8202  **/
8203 void
8204 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
8205                                       GtkTreeDestroyCountFunc  func,
8206                                       gpointer                 data,
8207                                       GtkDestroyNotify         destroy)
8208 {
8209   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8210
8211   if (tree_view->priv->destroy_count_destroy)
8212     (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
8213
8214   tree_view->priv->destroy_count_func = func;
8215   tree_view->priv->destroy_count_data = data;
8216   tree_view->priv->destroy_count_destroy = destroy;
8217 }