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