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