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