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