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