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