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