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