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