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