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