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