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