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