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