]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
leave threads before returning
[~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                   column->resized_width = MAX (column->min_width,
3376                                                column->resized_width);
3377                   column->use_resized_width = TRUE;
3378                   gtk_widget_queue_resize (widget);
3379                   return TRUE;
3380                 }
3381               else if (event->keyval == GDK_Right)
3382                 {
3383                   column->resized_width = MAX (column->resized_width,
3384                                                column->width);
3385                   column->resized_width += 2;
3386                   column->use_resized_width = TRUE;
3387                   gtk_widget_queue_resize (widget);
3388                   return TRUE;
3389                 }
3390             }
3391           list = list->next;
3392         }
3393     }
3394
3395   /* FIXME: broken when we go bidi? */
3396   if (tree_view->priv->columns && (event->state & GDK_CONTROL_MASK) &&
3397       (event->keyval == GDK_Left || event->keyval == GDK_Right
3398        || event->keyval == GDK_Home || event->keyval == GDK_End))
3399     {
3400       list = tree_view->priv->columns;
3401       while (list)
3402         {
3403           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
3404           if (GTK_WIDGET_HAS_FOCUS (column->button))
3405             {
3406               if (event->keyval == GDK_Left)
3407                 {
3408                   GtkTreeViewColumn *col;
3409                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
3410                   if (col != (GtkTreeViewColumn *)0x1)
3411                     gtk_tree_view_move_column_after (tree_view, column, col);
3412                   return TRUE;
3413                 }
3414               else if (event->keyval == GDK_Right)
3415                 {
3416                   GtkTreeViewColumn *col;
3417                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
3418                   if (col != (GtkTreeViewColumn *)0x1)
3419                     gtk_tree_view_move_column_after (tree_view, column, col);
3420                   return TRUE;
3421                 }
3422               else if (event->keyval == GDK_Home)
3423                 {
3424                   GtkTreeViewColumn *col;
3425                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
3426                   if (col != (GtkTreeViewColumn *)0x1)
3427                     gtk_tree_view_move_column_after (tree_view, column, col);
3428                   return TRUE;
3429                 }
3430               else if (event->keyval == GDK_End)
3431                 {
3432                   GtkTreeViewColumn *col;
3433                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
3434                   if (col != (GtkTreeViewColumn *)0x1)
3435                     gtk_tree_view_move_column_after (tree_view, column, col);
3436                   return TRUE;
3437                 }
3438             }
3439           list = list->next;
3440         }
3441     }
3442
3443   /* FIXME: this is prolly broken when we go bidi */
3444   if (tree_view->priv->columns &&
3445       (event->keyval == GDK_Left || event->keyval == GDK_Right))
3446     {
3447       gint width = 0;
3448       list = tree_view->priv->columns;
3449       while (list)
3450         {
3451           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
3452           if (GTK_WIDGET_HAS_FOCUS (column->button))
3453             {
3454               if (event->keyval == GDK_Left && list->prev)
3455                 {
3456                   GList *tmp;
3457
3458                   for (tmp = list->prev; tmp; tmp = tmp->prev)
3459                     if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
3460                       break;
3461
3462                   if (!tmp)
3463                     return FALSE;
3464
3465                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
3466                   gtk_widget_grab_focus (tree_view->priv->focus_column->button);
3467                   width -= tree_view->priv->focus_column->width;
3468                   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));
3469                   return TRUE;
3470                 }
3471               else if (event->keyval == GDK_Right && list->next)
3472                 {
3473                   GList *tmp;
3474
3475                   for (tmp = list->next; tmp; tmp = tmp->next)
3476                     if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
3477                       break;
3478
3479                   if (!tmp)
3480                     return FALSE;
3481
3482                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
3483
3484                   gtk_widget_grab_focus (tree_view->priv->focus_column->button);
3485                   width += tree_view->priv->focus_column->width;
3486                   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));
3487                   return TRUE;
3488                 }
3489             }
3490           width += GTK_TREE_VIEW_COLUMN (list->data)->width;
3491           list = list->next;
3492         }
3493     }
3494
3495   return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
3496 }
3497
3498 /* FIXME Is this function necessary? Can I get an enter_notify event
3499  * w/o either an expose event or a mouse motion event?
3500  */
3501 static gboolean
3502 gtk_tree_view_enter_notify (GtkWidget        *widget,
3503                             GdkEventCrossing *event)
3504 {
3505   GtkTreeView *tree_view;
3506   GtkRBTree *tree;
3507   GtkRBNode *node;
3508   gint new_y;
3509
3510   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3511
3512   tree_view = GTK_TREE_VIEW (widget);
3513
3514   /* Sanity check it */
3515   if (event->window != tree_view->priv->bin_window)
3516     return FALSE;
3517
3518   if (tree_view->priv->tree == NULL)
3519     return FALSE;
3520
3521   if ((tree_view->priv->button_pressed_node != NULL) &&
3522       (tree_view->priv->button_pressed_node != node))
3523     return TRUE;
3524
3525   /* find the node internally */
3526   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
3527   if (new_y < 0)
3528     new_y = 0;
3529   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3530
3531   if (node == NULL)
3532     return FALSE;
3533
3534   do_prelight (tree_view, tree, node, event->x, event->y);
3535
3536   if (tree_view->priv->prelight_node)
3537     _gtk_tree_view_queue_draw_node (tree_view,
3538                                    tree_view->priv->prelight_tree,
3539                                    tree_view->priv->prelight_node,
3540                                    NULL);
3541
3542   return TRUE;
3543 }
3544
3545 static gboolean
3546 gtk_tree_view_leave_notify (GtkWidget        *widget,
3547                             GdkEventCrossing *event)
3548 {
3549   GtkTreeView *tree_view;
3550
3551   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3552
3553   if (event->mode == GDK_CROSSING_GRAB)
3554     return TRUE;
3555   tree_view = GTK_TREE_VIEW (widget);
3556
3557   if (tree_view->priv->prelight_node)
3558     _gtk_tree_view_queue_draw_node (tree_view,
3559                                    tree_view->priv->prelight_tree,
3560                                    tree_view->priv->prelight_node,
3561                                    NULL);
3562
3563   ensure_unprelighted (tree_view);
3564
3565 return TRUE;
3566 }
3567
3568
3569 static gint
3570 gtk_tree_view_focus_out (GtkWidget     *widget,
3571                          GdkEventFocus *event)
3572 {
3573   GtkWidget   *search_dialog;
3574
3575   gtk_widget_queue_draw (widget);
3576
3577   /* destroy interactive search dialog */
3578   search_dialog = gtk_object_get_data (GTK_OBJECT (widget),
3579                                        GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
3580   if (search_dialog)
3581     gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget));
3582
3583   return FALSE;
3584 }
3585
3586
3587 /* Incremental Reflow
3588  */
3589
3590 /* Returns TRUE if it updated the size
3591  */
3592 static gboolean
3593 validate_row (GtkTreeView *tree_view,
3594               GtkRBTree   *tree,
3595               GtkRBNode   *node,
3596               GtkTreeIter *iter,
3597               GtkTreePath *path)
3598 {
3599   GtkTreeViewColumn *column;
3600   GList *list;
3601   gint height = 0;
3602   gint horizontal_separator;
3603   gint depth = gtk_tree_path_get_depth (path);
3604   gboolean retval = FALSE;
3605
3606   /* double check the row needs validating */
3607   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
3608       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3609     return FALSE;
3610
3611   gtk_widget_style_get (GTK_WIDGET (tree_view),
3612                         "horizontal_separator", &horizontal_separator,
3613                         NULL);
3614
3615   for (list = tree_view->priv->columns; list; list = list->next)
3616     {
3617       gint tmp_width;
3618       gint tmp_height;
3619
3620       column = list->data;
3621
3622       if (! column->visible)
3623         continue;
3624
3625       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
3626         continue;
3627
3628       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
3629                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3630                                                node->children?TRUE:FALSE);
3631       gtk_tree_view_column_cell_get_size (column,
3632                                           NULL, NULL, NULL,
3633                                           &tmp_width, &tmp_height);
3634       height = MAX (height, tmp_height);
3635       height = MAX (height, tree_view->priv->expander_size);
3636
3637       if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3638         {
3639           tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size);
3640         }
3641       else
3642         tmp_width = tmp_width + horizontal_separator;
3643
3644       if (tmp_width > column->requested_width)
3645         {
3646           retval = TRUE;
3647           column->requested_width = tmp_width;
3648         }
3649     }
3650
3651   if (height != GTK_RBNODE_GET_HEIGHT (node))
3652     {
3653       retval = TRUE;
3654       _gtk_rbtree_node_set_height (tree, node, height);
3655     }
3656   _gtk_rbtree_node_mark_valid (tree, node);
3657
3658   return retval;
3659 }
3660
3661
3662 static void
3663 validate_visible_area (GtkTreeView *tree_view)
3664 {
3665   GtkTreePath *path;
3666   GtkTreeIter iter;
3667   GtkRBTree *tree;
3668   GtkRBNode *node;
3669   gint y, height, offset;
3670   gboolean validated_area = FALSE;
3671   gboolean size_changed = FALSE;
3672   
3673   if (tree_view->priv->tree == NULL)
3674     return;
3675   
3676   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
3677     return;
3678   
3679   height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
3680
3681   y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0);
3682
3683   offset = _gtk_rbtree_find_offset (tree_view->priv->tree, y,
3684                                     &tree, &node);
3685   if (node == NULL)
3686     {
3687       path = gtk_tree_path_new_root ();
3688       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3689     }
3690   else
3691     {
3692       path = _gtk_tree_view_find_path (tree_view, tree, node);
3693       height += offset;
3694     }
3695
3696   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3697   do
3698     {
3699       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3700           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3701         {
3702           validated_area = TRUE;
3703           if (validate_row (tree_view, tree, node, &iter, path))
3704             size_changed = TRUE;
3705         }
3706       height -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
3707
3708       if (node->children)
3709         {
3710           GtkTreeIter parent = iter;
3711           gboolean has_child;
3712
3713           tree = node->children;
3714           node = tree->root;
3715
3716           g_assert (node != tree->nil);
3717
3718           while (node->left != tree->nil)
3719             node = node->left;
3720           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
3721                                                     &iter,
3722                                                     &parent);
3723           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
3724           gtk_tree_path_down (path);
3725         }
3726       else
3727         {
3728           gboolean done = FALSE;
3729           do
3730             {
3731               node = _gtk_rbtree_next (tree, node);
3732               if (node != NULL)
3733                 {
3734                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
3735                   done = TRUE;
3736
3737                   /* Sanity Check! */
3738                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
3739                 }
3740               else
3741                 {
3742                   GtkTreeIter parent_iter = iter;
3743                   gboolean has_parent;
3744
3745                   node = tree->parent_node;
3746                   tree = tree->parent_tree;
3747                   if (tree == NULL)
3748                     break;
3749                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
3750                                                            &iter,
3751                                                            &parent_iter);
3752
3753                   /* Sanity check */
3754                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
3755                 }
3756             }
3757           while (!done);
3758         }
3759     }
3760   while (node && height > 0);
3761
3762   if (size_changed)
3763     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3764   if (validated_area)
3765     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3766   if (path)
3767     gtk_tree_path_free (path);
3768 }
3769
3770 /* Our strategy for finding nodes to validate is a little convoluted.  We find
3771  * the left-most uninvalidated node.  We then try walking right, validating
3772  * nodes.  Once we find a valid node, we repeat the previous process of finding
3773  * the first invalid node.
3774  */
3775
3776 static gboolean
3777 validate_rows_handler (GtkTreeView *tree_view)
3778 {
3779   GtkRBTree *tree = NULL;
3780   GtkRBNode *node = NULL;
3781   gboolean validated_area = FALSE;
3782   gint retval = TRUE;
3783   GtkTreePath *path = NULL;
3784   GtkTreeIter iter;
3785   gint i = 0;
3786   g_assert (tree_view);
3787
3788   GDK_THREADS_ENTER ();
3789
3790   if (tree_view->priv->tree == NULL)
3791     {
3792       tree_view->priv->validate_rows_timer = 0;
3793       GDK_THREADS_LEAVE ();
3794       return FALSE;
3795     }
3796
3797   do
3798     {
3799
3800       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
3801         {
3802           retval = FALSE;
3803           goto done;
3804         }
3805
3806       if (path != NULL)
3807         {
3808           node = _gtk_rbtree_next (tree, node);
3809           if (node != NULL)
3810             {
3811               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
3812               gtk_tree_path_next (path);
3813             }
3814           else
3815             {
3816               gtk_tree_path_free (path);
3817               path = NULL;
3818             }
3819         }
3820
3821       if (path == NULL)
3822         {
3823           tree = tree_view->priv->tree;
3824           node = tree_view->priv->tree->root;
3825
3826           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
3827
3828           do
3829             {
3830               if (node->left != tree->nil &&
3831                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
3832                 {
3833                   node = node->left;
3834                 }
3835               else if (node->right != tree->nil &&
3836                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
3837                 {
3838                   node = node->right;
3839                 }
3840               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3841                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3842                 {
3843                   break;
3844                 }
3845               else if (node->children != NULL)
3846                 {
3847                   tree = node->children;
3848                   node = tree->root;
3849                 }
3850               else
3851                 /* RBTree corruption!  All bad */
3852                 g_assert_not_reached ();
3853             }
3854           while (TRUE);
3855           path = _gtk_tree_view_find_path (tree_view, tree, node);
3856           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3857         }
3858       validated_area = validate_row (tree_view, tree, node, &iter, path) | validated_area;
3859       i++;
3860     }
3861   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
3862   
3863  done:
3864   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
3865     gtk_tree_view_top_row_to_dy (tree_view);
3866   else
3867     gtk_tree_view_dy_to_top_row (tree_view);
3868
3869   if (path) gtk_tree_path_free (path);
3870   if (validated_area)
3871     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3872   if (! retval)
3873     tree_view->priv->validate_rows_timer = 0;
3874
3875   GDK_THREADS_LEAVE ();
3876
3877   return retval;
3878 }
3879
3880 static gboolean
3881 presize_handler_callback (gpointer data)
3882 {
3883   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3884
3885   GDK_THREADS_ENTER ();
3886
3887   if (tree_view->priv->mark_rows_col_dirty)
3888     {
3889       if (tree_view->priv->tree)
3890         _gtk_rbtree_column_invalid (tree_view->priv->tree);
3891       tree_view->priv->mark_rows_col_dirty = FALSE;
3892     }
3893   validate_visible_area (tree_view);
3894   tree_view->priv->presize_handler_timer = 0;
3895                    
3896   GDK_THREADS_LEAVE ();
3897
3898   return FALSE;
3899 }
3900
3901 static void
3902 install_presize_handler (GtkTreeView *tree_view)
3903 {
3904   if (! GTK_WIDGET_REALIZED (tree_view))
3905     return;
3906
3907   if (! tree_view->priv->presize_handler_timer)
3908     {
3909       tree_view->priv->presize_handler_timer =
3910         g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
3911     }
3912   if (! tree_view->priv->validate_rows_timer)
3913     {
3914       tree_view->priv->validate_rows_timer =
3915         g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
3916     }
3917 }
3918
3919 /* Always call this iff dy is in the visible range.  If the tree is empty, then
3920  * it's set to be NULL, and top_row_dy is 0;
3921  */
3922 static void
3923 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
3924 {
3925   GtkTreePath *path;
3926   GtkRBTree *tree;
3927   GtkRBNode *node;
3928
3929   gtk_tree_row_reference_free (tree_view->priv->top_row);
3930   if (tree_view->priv->tree == NULL)
3931     tree = NULL;
3932   else
3933     tree_view->priv->top_row_dy = _gtk_rbtree_find_offset (tree_view->priv->tree,
3934                                                            tree_view->priv->dy,
3935                                                            &tree, &node);
3936   if (tree == NULL)
3937     {
3938       tree_view->priv->top_row = NULL;
3939       tree_view->priv->top_row_dy = 0;
3940       return;
3941     }
3942       
3943   path = _gtk_tree_view_find_path (tree_view, tree, node);
3944   tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
3945   gtk_tree_path_free (path);
3946 }
3947
3948 static void
3949 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
3950 {
3951   GtkTreePath *path;
3952   GtkRBTree *tree;
3953   GtkRBNode *node;
3954
3955   if (tree_view->priv->top_row)
3956     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
3957   else
3958     path = NULL;
3959
3960   if (!path)
3961     tree = NULL;
3962   else
3963     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3964
3965   if (path)
3966     gtk_tree_path_free (path);
3967
3968   if (tree == NULL)
3969     {
3970       /* keep dy and set new toprow */
3971       gtk_tree_row_reference_free (tree_view->priv->top_row);
3972       tree_view->priv->top_row = NULL;
3973       tree_view->priv->top_row_dy = 0;
3974       gtk_tree_view_dy_to_top_row (tree_view);
3975       return;
3976     }
3977
3978   if (MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size)
3979       < tree_view->priv->top_row_dy)
3980     {
3981       /* new top row */
3982       gtk_tree_view_dy_to_top_row (tree_view);
3983       return;
3984     }
3985
3986   tree_view->priv->dy = _gtk_rbtree_node_find_offset (tree, node);
3987   tree_view->priv->dy += tree_view->priv->top_row_dy;
3988   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3989                             tree_view->priv->dy);
3990   gtk_adjustment_changed (tree_view->priv->vadjustment);
3991 }
3992
3993 void
3994 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
3995 {
3996   tree_view->priv->mark_rows_col_dirty = TRUE;
3997
3998   install_presize_handler (tree_view);
3999 }
4000
4001 /* Drag-and-drop */
4002
4003 static void
4004 set_source_row (GdkDragContext *context,
4005                 GtkTreeModel   *model,
4006                 GtkTreePath    *source_row)
4007 {
4008   g_object_set_data_full (G_OBJECT (context),
4009                           "gtk-tree-view-source-row",
4010                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
4011                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
4012 }
4013
4014 static GtkTreePath*
4015 get_source_row (GdkDragContext *context)
4016 {
4017   GtkTreeRowReference *ref =
4018     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
4019
4020   if (ref)
4021     return gtk_tree_row_reference_get_path (ref);
4022   else
4023     return NULL;
4024 }
4025
4026
4027 static void
4028 set_dest_row (GdkDragContext *context,
4029               GtkTreeModel   *model,
4030               GtkTreePath    *dest_row)
4031 {
4032   g_object_set_data_full (G_OBJECT (context),
4033                           "gtk-tree-view-dest-row",
4034                           dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
4035                           (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
4036 }
4037
4038 static GtkTreePath*
4039 get_dest_row (GdkDragContext *context)
4040 {
4041   GtkTreeRowReference *ref =
4042     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
4043
4044   if (ref)
4045     return gtk_tree_row_reference_get_path (ref);
4046   else
4047     return NULL;
4048 }
4049
4050 /* Get/set whether drag_motion requested the drag data and
4051  * drag_data_received should thus not actually insert the data,
4052  * since the data doesn't result from a drop.
4053  */
4054 static void
4055 set_status_pending (GdkDragContext *context,
4056                     GdkDragAction   suggested_action)
4057 {
4058   g_object_set_data (G_OBJECT (context),
4059                      "gtk-tree-view-status-pending",
4060                      GINT_TO_POINTER (suggested_action));
4061 }
4062
4063 static GdkDragAction
4064 get_status_pending (GdkDragContext *context)
4065 {
4066   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
4067                                              "gtk-tree-view-status-pending"));
4068 }
4069
4070 static TreeViewDragInfo*
4071 get_info (GtkTreeView *tree_view)
4072 {
4073   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
4074 }
4075
4076 static void
4077 clear_source_info (TreeViewDragInfo *di)
4078 {
4079   if (di->source_target_list)
4080     gtk_target_list_unref (di->source_target_list);
4081
4082   di->source_target_list = NULL;
4083 }
4084
4085 static void
4086 clear_dest_info (TreeViewDragInfo *di)
4087 {
4088   if (di->dest_target_list)
4089     gtk_target_list_unref (di->dest_target_list);
4090
4091   di->dest_target_list = NULL;
4092 }
4093
4094 static void
4095 destroy_info (TreeViewDragInfo *di)
4096 {
4097   clear_source_info (di);
4098   clear_dest_info (di);
4099   g_free (di);
4100 }
4101
4102 static TreeViewDragInfo*
4103 ensure_info (GtkTreeView *tree_view)
4104 {
4105   TreeViewDragInfo *di;
4106
4107   di = get_info (tree_view);
4108
4109   if (di == NULL)
4110     {
4111       di = g_new0 (TreeViewDragInfo, 1);
4112
4113       g_object_set_data_full (G_OBJECT (tree_view),
4114                               "gtk-tree-view-drag-info",
4115                               di,
4116                               (GDestroyNotify) destroy_info);
4117     }
4118
4119   return di;
4120 }
4121
4122 static void
4123 remove_info (GtkTreeView *tree_view)
4124 {
4125   g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
4126 }
4127
4128 #if 0
4129 static gint
4130 drag_scan_timeout (gpointer data)
4131 {
4132   GtkTreeView *tree_view;
4133   gint x, y;
4134   GdkModifierType state;
4135   GtkTreePath *path = NULL;
4136   GtkTreeViewColumn *column = NULL;
4137   GdkRectangle visible_rect;
4138
4139   GDK_THREADS_ENTER ();
4140
4141   tree_view = GTK_TREE_VIEW (data);
4142
4143   gdk_window_get_pointer (tree_view->priv->bin_window,
4144                           &x, &y, &state);
4145
4146   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4147
4148   /* See if we are near the edge. */
4149   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
4150       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
4151       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
4152       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
4153     {
4154       gtk_tree_view_get_path_at_pos (tree_view,
4155                                      tree_view->priv->bin_window,
4156                                      x, y,
4157                                      &path,
4158                                      &column,
4159                                      NULL,
4160                                      NULL);
4161
4162       if (path != NULL)
4163         {
4164           gtk_tree_view_scroll_to_cell (tree_view,
4165                                         path,
4166                                         column,
4167                                         TRUE,
4168                                         0.5, 0.5);
4169
4170           gtk_tree_path_free (path);
4171         }
4172     }
4173
4174   GDK_THREADS_LEAVE ();
4175
4176   return TRUE;
4177 }
4178 #endif /* 0 */
4179
4180 static void
4181 remove_scroll_timeout (GtkTreeView *tree_view)
4182 {
4183   if (tree_view->priv->scroll_timeout != 0)
4184     {
4185       gtk_timeout_remove (tree_view->priv->scroll_timeout);
4186       tree_view->priv->scroll_timeout = 0;
4187     }
4188 }
4189 static gboolean
4190 check_model_dnd (GtkTreeModel *model,
4191                  GType         required_iface,
4192                  const gchar  *signal)
4193 {
4194   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
4195     {
4196       g_warning ("You must override the default '%s' handler "
4197                  "on GtkTreeView when using models that don't support "
4198                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
4199                  "is to connect to '%s' and call "
4200                  "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
4201                  "the default handler from running. Look at the source code "
4202                  "for the default handler in gtktreeview.c to get an idea what "
4203                  "your handler should do. (gtktreeview.c is in the GTK source "
4204                  "code.) If you're using GTK from a language other than C, "
4205                  "there may be a more natural way to override default handlers, e.g. via derivation.",
4206                  signal, g_type_name (required_iface), signal);
4207       return FALSE;
4208     }
4209   else
4210     return TRUE;
4211 }
4212
4213 static void
4214 remove_open_timeout (GtkTreeView *tree_view)
4215 {
4216   if (tree_view->priv->open_dest_timeout != 0)
4217     {
4218       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
4219       tree_view->priv->open_dest_timeout = 0;
4220     }
4221 }
4222
4223
4224 static gint
4225 open_row_timeout (gpointer data)
4226 {
4227   GtkTreeView *tree_view = data;
4228   GtkTreePath *dest_path = NULL;
4229   GtkTreeViewDropPosition pos;
4230   gboolean result = FALSE;
4231
4232   GDK_THREADS_ENTER ();
4233
4234   gtk_tree_view_get_drag_dest_row (tree_view,
4235                                    &dest_path,
4236                                    &pos);
4237
4238   if (dest_path &&
4239       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4240        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
4241     {
4242       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
4243       tree_view->priv->open_dest_timeout = 0;
4244
4245       gtk_tree_path_free (dest_path);
4246     }
4247   else
4248     {
4249       if (dest_path)
4250         gtk_tree_path_free (dest_path);
4251
4252       result = TRUE;
4253     }
4254
4255   GDK_THREADS_LEAVE ();
4256
4257   return result;
4258 }
4259
4260 static gint
4261 scroll_row_timeout (gpointer data)
4262 {
4263   GtkTreeView *tree_view = data;
4264
4265   GDK_THREADS_ENTER ();
4266
4267   gtk_tree_view_vertical_autoscroll (tree_view);
4268
4269   GDK_THREADS_LEAVE ();
4270
4271   return TRUE;
4272 }
4273
4274 /* Returns TRUE if event should not be propagated to parent widgets */
4275 static gboolean
4276 set_destination_row (GtkTreeView    *tree_view,
4277                      GdkDragContext *context,
4278                      gint            x,
4279                      gint            y,
4280                      GdkDragAction  *suggested_action,
4281                      GdkAtom        *target)
4282 {
4283   GtkTreePath *path = NULL;
4284   GtkTreeViewDropPosition pos;
4285   GtkTreeViewDropPosition old_pos;
4286   TreeViewDragInfo *di;
4287   GtkWidget *widget;
4288   GtkTreePath *old_dest_path = NULL;
4289
4290   *suggested_action = 0;
4291   *target = GDK_NONE;
4292
4293   widget = GTK_WIDGET (tree_view);
4294
4295   di = get_info (tree_view);
4296
4297   if (di == NULL)
4298     {
4299       /* someone unset us as a drag dest, note that if
4300        * we return FALSE drag_leave isn't called
4301        */
4302
4303       gtk_tree_view_set_drag_dest_row (tree_view,
4304                                        NULL,
4305                                        GTK_TREE_VIEW_DROP_BEFORE);
4306
4307       remove_scroll_timeout (GTK_TREE_VIEW (widget));
4308       remove_open_timeout (GTK_TREE_VIEW (widget));
4309
4310       return FALSE; /* no longer a drop site */
4311     }
4312
4313   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
4314   if (*target == GDK_NONE)
4315     {
4316       return FALSE;
4317     }
4318
4319   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
4320                                           x, y,
4321                                           &path,
4322                                           &pos))
4323     {
4324       /* can't drop here */
4325       remove_open_timeout (tree_view);
4326
4327       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4328                                        NULL,
4329                                        GTK_TREE_VIEW_DROP_BEFORE);
4330
4331       /* don't propagate to parent though */
4332       return TRUE;
4333     }
4334
4335   g_assert (path);
4336
4337   /* If we left the current row's "open" zone, unset the timeout for
4338    * opening the row
4339    */
4340   gtk_tree_view_get_drag_dest_row (tree_view,
4341                                    &old_dest_path,
4342                                    &old_pos);
4343
4344   if (old_dest_path &&
4345       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
4346        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4347          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
4348     remove_open_timeout (tree_view);
4349
4350   if (old_dest_path)
4351     gtk_tree_path_free (old_dest_path);
4352
4353   if (TRUE /* FIXME if the location droppable predicate */)
4354     {
4355       GtkWidget *source_widget;
4356
4357       *suggested_action = context->suggested_action;
4358
4359       source_widget = gtk_drag_get_source_widget (context);
4360
4361       if (source_widget == widget)
4362         {
4363           /* Default to MOVE, unless the user has
4364            * pressed ctrl or alt to affect available actions
4365            */
4366           if ((context->actions & GDK_ACTION_MOVE) != 0)
4367             *suggested_action = GDK_ACTION_MOVE;
4368         }
4369
4370       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4371                                        path, pos);
4372     }
4373   else
4374     {
4375       /* can't drop here */
4376       remove_open_timeout (tree_view);
4377
4378       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4379                                        NULL,
4380                                        GTK_TREE_VIEW_DROP_BEFORE);
4381     }
4382
4383   return TRUE;
4384 }
4385 static GtkTreePath*
4386 get_logical_dest_row (GtkTreeView *tree_view)
4387
4388 {
4389   /* adjust path to point to the row the drop goes in front of */
4390   GtkTreePath *path = NULL;
4391   GtkTreeViewDropPosition pos;
4392
4393   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
4394
4395   if (path == NULL)
4396     return NULL;
4397
4398   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
4399     ; /* do nothing */
4400   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
4401            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
4402     {
4403       /* get first child, drop before it */
4404       gtk_tree_path_down (path);
4405     }
4406   else
4407     {
4408       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
4409       gtk_tree_path_next (path);
4410     }
4411
4412   return path;
4413 }
4414
4415 static gboolean
4416 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
4417                                         GdkEventMotion   *event)
4418 {
4419   GdkDragContext *context;
4420   TreeViewDragInfo *di;
4421   GtkTreePath *path = NULL;
4422   gint button;
4423   gint cell_x, cell_y;
4424   GtkTreeModel *model;
4425   gboolean retval = FALSE;
4426
4427   di = get_info (tree_view);
4428
4429   if (di == NULL)
4430     goto out;
4431
4432   if (tree_view->priv->pressed_button < 0)
4433     goto out;
4434
4435   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
4436                                  tree_view->priv->press_start_x,
4437                                  tree_view->priv->press_start_y,
4438                                  event->x, event->y))
4439     goto out;
4440
4441   model = gtk_tree_view_get_model (tree_view);
4442
4443   if (model == NULL)
4444     goto out;
4445
4446   button = tree_view->priv->pressed_button;
4447   tree_view->priv->pressed_button = -1;
4448
4449   gtk_tree_view_get_path_at_pos (tree_view,
4450                                  tree_view->priv->press_start_x,
4451                                  tree_view->priv->press_start_y,
4452                                  &path,
4453                                  NULL,
4454                                  &cell_x,
4455                                  &cell_y);
4456
4457   if (path == NULL)
4458     goto out;
4459
4460   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
4461       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
4462                                            path))
4463     goto out;
4464
4465   /* FIXME Check whether we're a start button, if not return FALSE and
4466    * free path
4467    */
4468
4469   /* Now we can begin the drag */
4470
4471   retval = TRUE;
4472
4473   context = gtk_drag_begin (GTK_WIDGET (tree_view),
4474                             di->source_target_list,
4475                             di->source_actions,
4476                             button,
4477                             (GdkEvent*)event);
4478
4479   gtk_drag_set_icon_default (context);
4480
4481   {
4482     GdkPixmap *row_pix;
4483
4484     row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
4485                                                   path);
4486
4487     gtk_drag_set_icon_pixmap (context,
4488                               gdk_drawable_get_colormap (row_pix),
4489                               row_pix,
4490                               NULL,
4491                               /* the + 1 is for the black border in the icon */
4492                               tree_view->priv->press_start_x + 1,
4493                               cell_y + 1);
4494
4495     gdk_pixmap_unref (row_pix);
4496   }
4497
4498   set_source_row (context, model, path);
4499
4500  out:
4501   if (path)
4502     gtk_tree_path_free (path);
4503
4504   return retval;
4505 }
4506
4507
4508 static void
4509 gtk_tree_view_drag_begin (GtkWidget      *widget,
4510                           GdkDragContext *context)
4511 {
4512   /* do nothing */
4513 }
4514
4515 static void
4516 gtk_tree_view_drag_end (GtkWidget      *widget,
4517                         GdkDragContext *context)
4518 {
4519   /* do nothing */
4520 }
4521
4522 /* Default signal implementations for the drag signals */
4523 static void
4524 gtk_tree_view_drag_data_get (GtkWidget        *widget,
4525                              GdkDragContext   *context,
4526                              GtkSelectionData *selection_data,
4527                              guint             info,
4528                              guint             time)
4529 {
4530   GtkTreeView *tree_view;
4531   GtkTreeModel *model;
4532   TreeViewDragInfo *di;
4533   GtkTreePath *source_row;
4534
4535   tree_view = GTK_TREE_VIEW (widget);
4536
4537   model = gtk_tree_view_get_model (tree_view);
4538
4539   if (model == NULL)
4540     return;
4541
4542   di = get_info (GTK_TREE_VIEW (widget));
4543
4544   if (di == NULL)
4545     return;
4546
4547   source_row = get_source_row (context);
4548
4549   if (source_row == NULL)
4550     return;
4551
4552   /* We can implement the GTK_TREE_MODEL_ROW target generically for
4553    * any model; for DragSource models there are some other targets
4554    * we also support.
4555    */
4556
4557   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
4558       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
4559                                           source_row,
4560                                           selection_data))
4561     goto done;
4562
4563   /* If drag_data_get does nothing, try providing row data. */
4564   if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
4565     {
4566       gtk_tree_set_row_drag_data (selection_data,
4567                                   model,
4568                                   source_row);
4569     }
4570
4571  done:
4572   gtk_tree_path_free (source_row);
4573 }
4574
4575
4576 static void
4577 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
4578                                 GdkDragContext *context)
4579 {
4580   TreeViewDragInfo *di;
4581   GtkTreeModel *model;
4582   GtkTreeView *tree_view;
4583   GtkTreePath *source_row;
4584
4585   tree_view = GTK_TREE_VIEW (widget);
4586   model = gtk_tree_view_get_model (tree_view);
4587
4588   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
4589     return;
4590
4591   di = get_info (tree_view);
4592
4593   if (di == NULL)
4594     return;
4595
4596   source_row = get_source_row (context);
4597
4598   if (source_row == NULL)
4599     return;
4600
4601   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
4602                                          source_row);
4603
4604   gtk_tree_path_free (source_row);
4605
4606   set_source_row (context, NULL, NULL);
4607 }
4608
4609 static void
4610 gtk_tree_view_drag_leave (GtkWidget      *widget,
4611                           GdkDragContext *context,
4612                           guint             time)
4613 {
4614   TreeViewDragInfo *di;
4615
4616   di = get_info (GTK_TREE_VIEW (widget));
4617
4618   /* unset any highlight row */
4619   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4620                                    NULL,
4621                                    GTK_TREE_VIEW_DROP_BEFORE);
4622
4623   remove_scroll_timeout (GTK_TREE_VIEW (widget));
4624   remove_open_timeout (GTK_TREE_VIEW (widget));
4625 }
4626
4627
4628 static gboolean
4629 gtk_tree_view_drag_motion (GtkWidget        *widget,
4630                            GdkDragContext   *context,
4631                            gint              x,
4632                            gint              y,
4633                            guint             time)
4634 {
4635   GtkTreePath *path = NULL;
4636   GtkTreeViewDropPosition pos;
4637   GtkTreeView *tree_view;
4638   GdkDragAction suggested_action = 0;
4639   GdkAtom target;
4640
4641   tree_view = GTK_TREE_VIEW (widget);
4642
4643   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
4644     return FALSE;
4645
4646   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
4647
4648   if (path == NULL)
4649     {
4650       /* Can't drop here. */
4651       gdk_drag_status (context, 0, time);
4652     }
4653   else
4654     {
4655       if (tree_view->priv->open_dest_timeout == 0 &&
4656           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4657            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
4658         {
4659           tree_view->priv->open_dest_timeout =
4660             gtk_timeout_add (500, open_row_timeout, tree_view);
4661         }
4662       else if (tree_view->priv->scroll_timeout == 0)
4663         {
4664           tree_view->priv->scroll_timeout =
4665             gtk_timeout_add (150, scroll_row_timeout, tree_view);
4666         }
4667
4668       if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
4669         {
4670           /* Request data so we can use the source row when
4671            * determining whether to accept the drop
4672            */
4673           set_status_pending (context, suggested_action);
4674           gtk_drag_get_data (widget, context, target, time);
4675         }
4676       else
4677         {
4678           set_status_pending (context, 0);
4679           gdk_drag_status (context, suggested_action, time);
4680         }
4681     }
4682
4683   if (path)
4684     gtk_tree_path_free (path);
4685
4686   return TRUE;
4687 }
4688
4689
4690 static gboolean
4691 gtk_tree_view_drag_drop (GtkWidget        *widget,
4692                          GdkDragContext   *context,
4693                          gint              x,
4694                          gint              y,
4695                          guint             time)
4696 {
4697   GtkTreeView *tree_view;
4698   GtkTreePath *path;
4699   GdkDragAction suggested_action = 0;
4700   GdkAtom target = GDK_NONE;
4701   TreeViewDragInfo *di;
4702   GtkTreeModel *model;
4703
4704   tree_view = GTK_TREE_VIEW (widget);
4705
4706   model = gtk_tree_view_get_model (tree_view);
4707
4708   remove_scroll_timeout (GTK_TREE_VIEW (widget));
4709   remove_open_timeout (GTK_TREE_VIEW (widget));
4710
4711   di = get_info (tree_view);
4712
4713   if (di == NULL)
4714     return FALSE;
4715
4716   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
4717     return FALSE;
4718
4719   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
4720     return FALSE;
4721
4722   path = get_logical_dest_row (tree_view);
4723
4724   if (target != GDK_NONE && path != NULL)
4725     {
4726       /* in case a motion had requested drag data, change things so we
4727        * treat drag data receives as a drop.
4728        */
4729       set_status_pending (context, 0);
4730
4731       set_dest_row (context, model, path);
4732     }
4733
4734   if (path)
4735     gtk_tree_path_free (path);
4736
4737   /* Unset this thing */
4738   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4739                                    NULL,
4740                                    GTK_TREE_VIEW_DROP_BEFORE);
4741
4742   if (target != GDK_NONE)
4743     {
4744       gtk_drag_get_data (widget, context, target, time);
4745       return TRUE;
4746     }
4747   else
4748     return FALSE;
4749 }
4750
4751 static void
4752 gtk_tree_view_drag_data_received (GtkWidget        *widget,
4753                                   GdkDragContext   *context,
4754                                   gint              x,
4755                                   gint              y,
4756                                   GtkSelectionData *selection_data,
4757                                   guint             info,
4758                                   guint             time)
4759 {
4760   GtkTreePath *path;
4761   TreeViewDragInfo *di;
4762   gboolean accepted = FALSE;
4763   GtkTreeModel *model;
4764   GtkTreeView *tree_view;
4765   GtkTreePath *dest_row;
4766   GdkDragAction suggested_action;
4767
4768   tree_view = GTK_TREE_VIEW (widget);
4769
4770   model = gtk_tree_view_get_model (tree_view);
4771
4772   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
4773     return;
4774
4775   di = get_info (tree_view);
4776
4777   if (di == NULL)
4778     return;
4779
4780   suggested_action = get_status_pending (context);
4781
4782   if (suggested_action)
4783     {
4784       /* We are getting this data due to a request in drag_motion,
4785        * rather than due to a request in drag_drop, so we are just
4786        * supposed to call drag_status, not actually paste in the
4787        * data.
4788        */
4789       path = get_logical_dest_row (tree_view);
4790
4791       if (path == NULL)
4792         suggested_action = 0;
4793
4794       if (suggested_action)
4795         {
4796           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
4797                                                      path,
4798                                                      selection_data))
4799             suggested_action = 0;
4800         }
4801
4802       gdk_drag_status (context, suggested_action, time);
4803
4804       if (path)
4805         gtk_tree_path_free (path);
4806
4807       /* If you can't drop, remove user drop indicator until the next motion */
4808       if (suggested_action == 0)
4809         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4810                                          NULL,
4811                                          GTK_TREE_VIEW_DROP_BEFORE);
4812
4813       return;
4814     }
4815
4816   dest_row = get_dest_row (context);
4817
4818   if (dest_row == NULL)
4819     return;
4820
4821   if (selection_data->length >= 0)
4822     {
4823       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
4824                                                  dest_row,
4825                                                  selection_data))
4826         accepted = TRUE;
4827     }
4828
4829   gtk_drag_finish (context,
4830                    accepted,
4831                    (context->action == GDK_ACTION_MOVE),
4832                    time);
4833
4834   gtk_tree_path_free (dest_row);
4835
4836   /* drop dest_row */
4837   set_dest_row (context, NULL, NULL);
4838 }
4839
4840
4841
4842 /* GtkContainer Methods
4843  */
4844
4845
4846 static void
4847 gtk_tree_view_remove (GtkContainer *container,
4848                       GtkWidget    *widget)
4849 {
4850   GtkTreeView *tree_view;
4851   GtkTreeViewChild *child = NULL;
4852   GList *tmp_list;
4853
4854   g_return_if_fail (GTK_IS_TREE_VIEW (container));
4855
4856   tree_view = GTK_TREE_VIEW (container);
4857
4858   tmp_list = tree_view->priv->children;
4859   while (tmp_list)
4860     {
4861       child = tmp_list->data;
4862       if (child->widget == widget)
4863         {
4864           gtk_widget_unparent (widget);
4865
4866           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
4867           g_list_free_1 (tmp_list);
4868           g_free (child);
4869           return;
4870         }
4871
4872       tmp_list = tmp_list->next;
4873     }
4874
4875   tmp_list = tree_view->priv->columns;
4876
4877   while (tmp_list)
4878     {
4879       GtkTreeViewColumn *column;
4880       column = tmp_list->data;
4881       if (column->button == widget)
4882         {
4883           gtk_widget_unparent (widget);
4884           return;
4885         }
4886       tmp_list = tmp_list->next;
4887     }
4888 }
4889
4890 static void
4891 gtk_tree_view_forall (GtkContainer *container,
4892                       gboolean      include_internals,
4893                       GtkCallback   callback,
4894                       gpointer      callback_data)
4895 {
4896   GtkTreeView *tree_view;
4897   GtkTreeViewChild *child = NULL;
4898   GtkTreeViewColumn *column;
4899   GList *tmp_list;
4900
4901   g_return_if_fail (GTK_IS_TREE_VIEW (container));
4902   g_return_if_fail (callback != NULL);
4903
4904   tree_view = GTK_TREE_VIEW (container);
4905
4906   tmp_list = tree_view->priv->children;
4907   while (tmp_list)
4908     {
4909       child = tmp_list->data;
4910       tmp_list = tmp_list->next;
4911
4912       (* callback) (child->widget, callback_data);
4913     }
4914   if (include_internals == FALSE)
4915     return;
4916
4917   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
4918     {
4919       column = tmp_list->data;
4920
4921       if (column->button)
4922         (* callback) (column->button, callback_data);
4923     }
4924 }
4925
4926 /* Returns TRUE if the focus is within the headers, after the focus operation is
4927  * done
4928  */
4929 static gboolean
4930 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
4931                             GtkDirectionType  dir)
4932 {
4933   GtkWidget *focus_child;
4934   GtkContainer *container;
4935
4936   GList *last_column, *first_column;
4937   GList *tmp_list;
4938
4939   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
4940     return FALSE;
4941
4942   focus_child = GTK_CONTAINER (tree_view)->focus_child;
4943   container = GTK_CONTAINER (tree_view);
4944
4945   last_column = g_list_last (tree_view->priv->columns);
4946   while (last_column)
4947     {
4948       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
4949           GTK_TREE_VIEW_COLUMN (last_column->data)->clickable &&
4950           GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable &&
4951           GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
4952         break;
4953       last_column = last_column->prev;
4954     }
4955
4956   /* No headers are visible, or are focusable.  We can't focus in or out.
4957    */
4958   if (last_column == NULL)
4959     return FALSE;
4960
4961   first_column = tree_view->priv->columns;
4962   while (first_column)
4963     {
4964       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
4965           GTK_TREE_VIEW_COLUMN (first_column->data)->clickable &&
4966           GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable &&
4967           GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
4968         break;
4969       first_column = first_column->next;
4970     }
4971
4972   switch (dir)
4973     {
4974     case GTK_DIR_TAB_BACKWARD:
4975     case GTK_DIR_TAB_FORWARD:
4976     case GTK_DIR_UP:
4977     case GTK_DIR_DOWN:
4978       if (focus_child == NULL)
4979         {
4980           if (tree_view->priv->focus_column != NULL)
4981             focus_child = tree_view->priv->focus_column->button;
4982           else
4983             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
4984           gtk_widget_grab_focus (focus_child);
4985           break;
4986         }
4987       return FALSE;
4988
4989     case GTK_DIR_LEFT:
4990     case GTK_DIR_RIGHT:
4991       if (focus_child == NULL)
4992         {
4993           if (tree_view->priv->focus_column != NULL)
4994             focus_child = tree_view->priv->focus_column->button;
4995           else if (dir == GTK_DIR_LEFT)
4996             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
4997           else
4998             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
4999           gtk_widget_grab_focus (focus_child);
5000           break;
5001         }
5002
5003       if (gtk_widget_child_focus (focus_child, dir))
5004         {
5005           /* The focus moves inside the button. */
5006           /* This is probably a great example of bad UI */
5007           break;
5008         }
5009
5010       /* We need to move the focus among the row of buttons. */
5011       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
5012         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
5013           break;
5014
5015       if (tmp_list == first_column && dir == GTK_DIR_LEFT)
5016         {
5017           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
5018           gtk_widget_grab_focus (focus_child);
5019           break;
5020         }
5021       else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
5022         {
5023           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
5024           gtk_widget_grab_focus (focus_child);
5025           break;
5026         }
5027
5028       while (tmp_list)
5029         {
5030           GtkTreeViewColumn *column;
5031
5032           if (dir == GTK_DIR_RIGHT)
5033             tmp_list = tmp_list->next;
5034           else
5035             tmp_list = tmp_list->prev;
5036
5037           if (tmp_list == NULL)
5038             {
5039               g_warning ("Internal button not found");
5040               break;
5041             }
5042           column = tmp_list->data;
5043           if (column->button &&
5044               column->visible &&
5045               GTK_WIDGET_CAN_FOCUS (column->button))
5046             {
5047               focus_child = column->button;
5048               gtk_widget_grab_focus (column->button);
5049               break;
5050             }
5051         }
5052       break;
5053     default:
5054       g_assert_not_reached ();
5055       break;
5056     }
5057
5058   /* if focus child is non-null, we assume it's been set to the current focus child
5059    */
5060   if (focus_child)
5061     {
5062       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
5063         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
5064           break;
5065
5066       tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5067
5068       /* If the following isn't true, then the view is smaller then the scrollpane.
5069        */
5070       if ((focus_child->allocation.x + focus_child->allocation.width) <=
5071           (tree_view->priv->hadjustment->upper))
5072         {
5073           /* Scroll to the button, if needed */
5074           if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
5075               (focus_child->allocation.x + focus_child->allocation.width))
5076             gtk_adjustment_set_value (tree_view->priv->hadjustment,
5077                                       focus_child->allocation.x + focus_child->allocation.width -
5078                                       tree_view->priv->hadjustment->page_size);
5079           else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
5080             gtk_adjustment_set_value (tree_view->priv->hadjustment,
5081                                       focus_child->allocation.x);
5082         }
5083     }
5084
5085   return (focus_child != NULL);
5086 }
5087
5088 static gint
5089 gtk_tree_view_focus (GtkWidget        *widget,
5090                      GtkDirectionType  direction)
5091 {
5092   GtkTreeView *tree_view;
5093   GtkWidget *focus_child;
5094   GtkContainer *container;
5095
5096   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
5097   g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
5098
5099   container = GTK_CONTAINER (widget);
5100   tree_view = GTK_TREE_VIEW (widget);
5101
5102   if (!GTK_WIDGET_IS_SENSITIVE (container))
5103     return FALSE;
5104
5105   focus_child = container->focus_child;
5106
5107   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
5108   /* Case 1.  Headers currently have focus. */
5109   if (focus_child)
5110     {
5111       switch (direction)
5112         {
5113         case GTK_DIR_LEFT:
5114         case GTK_DIR_RIGHT:
5115           gtk_tree_view_header_focus (tree_view, direction);
5116           return TRUE;
5117         case GTK_DIR_TAB_BACKWARD:
5118         case GTK_DIR_UP:
5119           return FALSE;
5120         case GTK_DIR_TAB_FORWARD:
5121         case GTK_DIR_DOWN:
5122           if (tree_view->priv->tree == NULL)
5123             return FALSE;
5124           gtk_tree_view_focus_to_cursor (tree_view);
5125           return TRUE;
5126         }
5127     }
5128
5129   /* Case 2. We don't have focus at all. */
5130   if (!GTK_WIDGET_HAS_FOCUS (container))
5131     {
5132       if (tree_view->priv->tree == NULL &&
5133           (direction == GTK_DIR_TAB_BACKWARD ||
5134            direction == GTK_DIR_UP))
5135         return gtk_tree_view_header_focus (tree_view, direction);
5136       if (((direction == GTK_DIR_TAB_FORWARD) ||
5137            (direction == GTK_DIR_RIGHT) ||
5138            (direction == GTK_DIR_DOWN) ||
5139            (direction == GTK_DIR_LEFT)) &&
5140           gtk_tree_view_header_focus (tree_view, direction))
5141         return TRUE;
5142
5143       if (tree_view->priv->tree == NULL)
5144         return FALSE;
5145       gtk_tree_view_focus_to_cursor (tree_view);
5146       return TRUE;
5147     }
5148
5149   /* Case 3. We have focus already. */
5150   if (tree_view->priv->tree == NULL)
5151     return gtk_tree_view_header_focus (tree_view, direction);
5152
5153   if (direction == GTK_DIR_TAB_BACKWARD)
5154     return (gtk_tree_view_header_focus (tree_view, direction));
5155   else if (direction == GTK_DIR_TAB_FORWARD)
5156     return FALSE;
5157
5158   /* Other directions caught by the keybindings */
5159   gtk_tree_view_focus_to_cursor (tree_view);
5160   return TRUE;
5161 }
5162
5163 static void
5164 gtk_tree_view_style_set (GtkWidget *widget,
5165                          GtkStyle *previous_style)
5166 {
5167   GtkTreeView *tree_view;
5168   GList *list;
5169   GtkTreeViewColumn *column;
5170
5171   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
5172
5173   tree_view = GTK_TREE_VIEW (widget);
5174
5175   gtk_widget_style_get (widget,
5176                         "expander_size", &tree_view->priv->expander_size,
5177                         NULL);
5178   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
5179
5180   for (list = tree_view->priv->columns; list; list = list->next)
5181     {
5182       column = list->data;
5183       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
5184     }
5185
5186   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
5187
5188   gtk_widget_queue_resize (widget);
5189 }
5190
5191
5192 static void
5193 gtk_tree_view_set_focus_child (GtkContainer *container,
5194                                GtkWidget    *child)
5195 {
5196   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
5197   GList *list;
5198
5199   for (list = tree_view->priv->columns; list; list = list->next)
5200     {
5201       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
5202         {
5203           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
5204           break;
5205         }
5206     }
5207
5208   (* parent_class->set_focus_child) (container, child);
5209 }
5210
5211 static void
5212 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
5213                                GtkAdjustment *hadj,
5214                                GtkAdjustment *vadj)
5215 {
5216   gboolean need_adjust = FALSE;
5217
5218   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5219
5220   if (hadj)
5221     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
5222   else
5223     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
5224   if (vadj)
5225     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
5226   else
5227     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
5228
5229   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
5230     {
5231       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
5232       gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
5233     }
5234
5235   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
5236     {
5237       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
5238       gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
5239     }
5240
5241   if (tree_view->priv->hadjustment != hadj)
5242     {
5243       tree_view->priv->hadjustment = hadj;
5244       gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
5245       gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
5246
5247       gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
5248                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
5249                           tree_view);
5250       need_adjust = TRUE;
5251     }
5252
5253   if (tree_view->priv->vadjustment != vadj)
5254     {
5255       tree_view->priv->vadjustment = vadj;
5256       gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
5257       gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
5258
5259       gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
5260                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
5261                           tree_view);
5262       need_adjust = TRUE;
5263     }
5264
5265   if (need_adjust)
5266     gtk_tree_view_adjustment_changed (NULL, tree_view);
5267 }
5268
5269
5270 static gboolean
5271 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
5272                                 GtkMovementStep    step,
5273                                 gint               count)
5274 {
5275   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5276   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
5277                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
5278                         step == GTK_MOVEMENT_DISPLAY_LINES ||
5279                         step == GTK_MOVEMENT_PAGES ||
5280                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
5281
5282   if (tree_view->priv->tree == NULL)
5283     return FALSE;
5284   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
5285     return FALSE;
5286
5287   gtk_tree_view_stop_editing (tree_view, FALSE);
5288   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
5289   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5290
5291   switch (step)
5292     {
5293       /* currently we make no distinction.  When we go bi-di, we need to */
5294     case GTK_MOVEMENT_LOGICAL_POSITIONS:
5295     case GTK_MOVEMENT_VISUAL_POSITIONS:
5296       gtk_tree_view_move_cursor_left_right (tree_view, count);
5297       break;
5298     case GTK_MOVEMENT_DISPLAY_LINES:
5299       gtk_tree_view_move_cursor_up_down (tree_view, count);
5300       break;
5301     case GTK_MOVEMENT_PAGES:
5302       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
5303       break;
5304     case GTK_MOVEMENT_BUFFER_ENDS:
5305       gtk_tree_view_move_cursor_start_end (tree_view, count);
5306       break;
5307     default:
5308       g_assert_not_reached ();
5309     }
5310
5311   return TRUE;
5312 }
5313
5314 static void
5315 gtk_tree_view_put (GtkTreeView *tree_view,
5316                    GtkWidget   *child_widget,
5317                    gint         x,
5318                    gint         y,
5319                    gint         width,
5320                    gint         height)
5321 {
5322   GtkTreeViewChild *child;
5323
5324   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5325   g_return_if_fail (GTK_IS_WIDGET (child_widget));
5326
5327   child = g_new (GtkTreeViewChild, 1);
5328
5329   child->widget = child_widget;
5330   child->x = x;
5331   child->y = y;
5332   child->width = width;
5333   child->height = height;
5334
5335   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
5336
5337   if (GTK_WIDGET_REALIZED (tree_view))
5338     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
5339
5340   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
5341 }
5342
5343 void
5344 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
5345                                   GtkWidget   *widget,
5346                                   gint         x,
5347                                   gint         y,
5348                                   gint         width,
5349                                   gint         height)
5350 {
5351   GtkTreeViewChild *child = NULL;
5352   GList *list;
5353   GdkRectangle allocation;
5354
5355   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5356   g_return_if_fail (GTK_IS_WIDGET (widget));
5357
5358   for (list = tree_view->priv->children; list; list = list->next)
5359     {
5360       if (((GtkTreeViewChild *)list->data)->widget == widget)
5361         {
5362           child = list->data;
5363           break;
5364         }
5365     }
5366   if (child == NULL)
5367     return;
5368
5369   allocation.x = child->x = x;
5370   allocation.y = child->y = y;
5371   allocation.width = child->width = width;
5372   allocation.height = child->height = height;
5373
5374   if (GTK_WIDGET_REALIZED (widget))
5375     gtk_widget_size_allocate (widget, &allocation);
5376 }
5377
5378
5379 /* TreeModel Callbacks
5380  */
5381
5382 static void
5383 gtk_tree_view_row_changed (GtkTreeModel *model,
5384                            GtkTreePath  *path,
5385                            GtkTreeIter  *iter,
5386                            gpointer      data)
5387 {
5388   GtkTreeView *tree_view = (GtkTreeView *)data;
5389   GtkRBTree *tree;
5390   GtkRBNode *node;
5391   gboolean free_path = FALSE;
5392   gint vertical_separator;
5393   GList *list;
5394
5395   g_return_if_fail (path != NULL || iter != NULL);
5396
5397   if (!GTK_WIDGET_REALIZED (tree_view))
5398     /* We can just ignore ::changed signals if we aren't realized, as we don't care about sizes
5399      */
5400     return;
5401
5402   gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
5403
5404   if (path == NULL)
5405     {
5406       path = gtk_tree_model_get_path (model, iter);
5407       free_path = TRUE;
5408     }
5409   else if (iter == NULL)
5410     gtk_tree_model_get_iter (model, iter, path);
5411
5412   if (_gtk_tree_view_find_node (tree_view,
5413                                 path,
5414                                 &tree,
5415                                 &node))
5416     /* We aren't actually showing the node */
5417     goto done;
5418
5419   if (tree == NULL)
5420     goto done;
5421
5422   _gtk_rbtree_node_mark_invalid (tree, node);
5423   for (list = tree_view->priv->columns; list; list = list->next)
5424     {
5425       GtkTreeViewColumn *column;
5426
5427       column = list->data;
5428       if (! column->visible)
5429         continue;
5430
5431       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5432         {
5433           _gtk_tree_view_column_cell_set_dirty (column, TRUE);
5434         }
5435     }
5436
5437  done:
5438   install_presize_handler (tree_view);
5439   if (free_path)
5440     gtk_tree_path_free (path);
5441 }
5442
5443 static void
5444 gtk_tree_view_row_inserted (GtkTreeModel *model,
5445                             GtkTreePath  *path,
5446                             GtkTreeIter  *iter,
5447                             gpointer      data)
5448 {
5449   GtkTreeView *tree_view = (GtkTreeView *) data;
5450   gint *indices;
5451   GtkRBTree *tmptree, *tree;
5452   GtkRBNode *tmpnode = NULL;
5453   gint depth;
5454   gint i = 0;
5455   gboolean free_path = FALSE;
5456
5457   g_return_if_fail (path != NULL || iter != NULL);
5458
5459   if (path == NULL)
5460     {
5461       path = gtk_tree_model_get_path (model, iter);
5462       free_path = TRUE;
5463     }
5464   else if (iter == NULL)
5465     gtk_tree_model_get_iter (model, iter, path);
5466
5467   if (tree_view->priv->tree == NULL)
5468     tree_view->priv->tree = _gtk_rbtree_new ();
5469
5470   tmptree = tree = tree_view->priv->tree;
5471
5472   /* Update all row-references */
5473   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
5474   depth = gtk_tree_path_get_depth (path);
5475   indices = gtk_tree_path_get_indices (path);
5476
5477   /* First, find the parent tree */
5478   while (i < depth - 1)
5479     {
5480       if (tmptree == NULL)
5481         {
5482           /* We aren't showing the node */
5483           goto done;
5484         }
5485
5486       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5487       if (tmpnode == NULL)
5488         {
5489           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
5490                      "This possibly means that a GtkTreeModel inserted a child node\n" \
5491                      "before the parent was inserted.");
5492           goto done;
5493         }
5494       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
5495         {
5496           /* FIXME enforce correct behavior on model, probably */
5497           /* In theory, the model should have emitted has_child_toggled here.  We
5498            * try to catch it anyway, just to be safe, in case the model hasn't.
5499            */
5500           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
5501                                                            tree,
5502                                                            tmpnode);
5503           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
5504           gtk_tree_path_free (tmppath);
5505           goto done;
5506         }
5507
5508       tmptree = tmpnode->children;
5509       tree = tmptree;
5510       i++;
5511     }
5512
5513   if (tree == NULL)
5514     goto done;
5515
5516   /* ref the node */
5517   gtk_tree_model_ref_node (tree_view->priv->model, iter);
5518   if (indices[depth - 1] == 0)
5519     {
5520       tmpnode = _gtk_rbtree_find_count (tree, 1);
5521       _gtk_rbtree_insert_before (tree, tmpnode, 0, FALSE);
5522     }
5523   else
5524     {
5525       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
5526       _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE);
5527     }
5528
5529  done:
5530   install_presize_handler (tree_view);
5531   if (free_path)
5532     gtk_tree_path_free (path);
5533 }
5534
5535 static void
5536 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
5537                                      GtkTreePath  *path,
5538                                      GtkTreeIter  *iter,
5539                                      gpointer      data)
5540 {
5541   GtkTreeView *tree_view = (GtkTreeView *)data;
5542   GtkTreeIter real_iter;
5543   gboolean has_child;
5544   GtkRBTree *tree;
5545   GtkRBNode *node;
5546   gboolean free_path = FALSE;
5547
5548   g_return_if_fail (path != NULL || iter != NULL);
5549
5550   if (iter)
5551     real_iter = *iter;
5552
5553   if (path == NULL)
5554     {
5555       path = gtk_tree_model_get_path (model, iter);
5556       free_path = TRUE;
5557     }
5558   else if (iter == NULL)
5559     gtk_tree_model_get_iter (model, &real_iter, path);
5560
5561   if (_gtk_tree_view_find_node (tree_view,
5562                                 path,
5563                                 &tree,
5564                                 &node))
5565     /* We aren't actually showing the node */
5566     goto done;
5567
5568   if (tree == NULL)
5569     goto done;
5570
5571   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
5572   /* Sanity check.
5573    */
5574   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
5575     goto done;
5576
5577   if (has_child)
5578     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
5579   else
5580     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
5581
5582   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
5583     {
5584       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
5585       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
5586         {
5587           GList *list;
5588
5589           for (list = tree_view->priv->columns; list; list = list->next)
5590             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
5591               {
5592                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
5593                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
5594                 break;
5595               }
5596         }
5597       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5598     }
5599   else
5600     {
5601       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5602     }
5603
5604  done:
5605   if (free_path)
5606     gtk_tree_path_free (path);
5607 }
5608
5609 static void
5610 count_children_helper (GtkRBTree *tree,
5611                        GtkRBNode *node,
5612                        gpointer   data)
5613 {
5614   if (node->children)
5615     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
5616   (*((gint *)data))++;
5617 }
5618
5619 static void
5620 gtk_tree_view_row_deleted (GtkTreeModel *model,
5621                            GtkTreePath  *path,
5622                            gpointer      data)
5623 {
5624   GtkTreeView *tree_view = (GtkTreeView *)data;
5625   GtkRBTree *tree;
5626   GtkRBNode *node;
5627   GList *list;
5628   gint selection_changed;
5629
5630   g_return_if_fail (path != NULL);
5631
5632   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
5633
5634   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5635     return;
5636
5637   if (tree == NULL)
5638     return;
5639
5640   /* Change the selection */
5641   selection_changed = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
5642
5643   for (list = tree_view->priv->columns; list; list = list->next)
5644     if (((GtkTreeViewColumn *)list->data)->visible &&
5645         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5646       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
5647
5648   /* Ensure we don't have a dangling pointer to a dead node */
5649   ensure_unprelighted (tree_view);
5650
5651   /* Cancel editting if we've started */
5652   gtk_tree_view_stop_editing (tree_view, TRUE);
5653
5654   /* If we have a node expanded/collapsed timeout, remove it */
5655   if (tree_view->priv->expand_collapse_timeout != 0)
5656     {
5657       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
5658       tree_view->priv->expand_collapse_timeout = 0;
5659
5660       /* Reset node */
5661       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
5662       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
5663       tree_view->priv->expanded_collapsed_node = NULL;
5664     }
5665
5666   if (tree_view->priv->destroy_count_func)
5667     {
5668       gint child_count = 0;
5669       if (node->children)
5670         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
5671       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
5672     }
5673
5674   if (tree->root->count == 1)
5675     {
5676       if (tree_view->priv->tree == tree)
5677         tree_view->priv->tree = NULL;
5678
5679       _gtk_rbtree_remove (tree);
5680     }
5681   else
5682     {
5683       _gtk_rbtree_remove_node (tree, node);
5684     }
5685
5686   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
5687     gtk_tree_view_top_row_to_dy (tree_view);
5688   else
5689     gtk_tree_view_dy_to_top_row (tree_view);
5690
5691   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5692
5693   if (selection_changed)
5694     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
5695 }
5696
5697
5698 static void
5699 gtk_tree_view_rows_reordered (GtkTreeModel *model,
5700                               GtkTreePath  *parent,
5701                               GtkTreeIter  *iter,
5702                               gint         *new_order,
5703                               gpointer      data)
5704 {
5705   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
5706   GtkRBTree *tree;
5707   GtkRBNode *node;
5708   gint len;
5709
5710   len = gtk_tree_model_iter_n_children (model, iter);
5711
5712   if (len < 2)
5713     return;
5714
5715   gtk_tree_row_reference_reordered (G_OBJECT (data),
5716                                     parent,
5717                                     iter,
5718                                     new_order);
5719
5720   if (_gtk_tree_view_find_node (tree_view,
5721                                 parent,
5722                                 &tree,
5723                                 &node))
5724     return;
5725
5726   /* We need to special case the parent path */
5727   if (tree == NULL)
5728     tree = tree_view->priv->tree;
5729   else
5730     tree = node->children;
5731
5732   if (tree == NULL)
5733     return;
5734
5735   /* we need to be unprelighted */
5736   ensure_unprelighted (tree_view);
5737   
5738   _gtk_rbtree_reorder (tree, new_order, len);
5739
5740   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
5741
5742   gtk_tree_view_dy_to_top_row (tree_view);
5743 }
5744
5745
5746 /* Internal tree functions
5747  */
5748
5749
5750 static void
5751 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
5752                                      GtkRBTree         *tree,
5753                                      GtkTreeViewColumn *column,
5754                                      gint              *x1,
5755                                      gint              *x2)
5756 {
5757   GtkTreeViewColumn *tmp_column = NULL;
5758   gint total_width;
5759   GList *list;
5760
5761   if (x1)
5762     *x1 = 0;
5763
5764   if (x2)
5765     *x2 = 0;
5766
5767   total_width = 0;
5768   for (list = tree_view->priv->columns; list; list = list->next)
5769     {
5770       tmp_column = list->data;
5771
5772       if (tmp_column == column)
5773         break;
5774
5775       if (tmp_column->visible)
5776         total_width += tmp_column->width;
5777     }
5778
5779   if (tmp_column != column)
5780     {
5781       g_warning (G_STRLOC": passed-in column isn't in the tree");
5782       return;
5783     }
5784
5785   if (x1)
5786     *x1 = total_width;
5787
5788   if (x2)
5789     {
5790       if (column->visible)
5791         *x2 = total_width + column->width;
5792       else
5793         *x2 = total_width; /* width of 0 */
5794     }
5795 }
5796 static void
5797 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
5798                                 GtkRBTree   *tree,
5799                                 gint        *x1,
5800                                 gint        *x2)
5801 {
5802   gint x_offset = 0;
5803   GList *list;
5804   GtkTreeViewColumn *tmp_column = NULL;
5805   gint total_width;
5806   gboolean indent_expanders;
5807
5808   total_width = 0;
5809   for (list = tree_view->priv->columns; list; list = list->next)
5810     {
5811       tmp_column = list->data;
5812
5813       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
5814         {
5815           x_offset = total_width;
5816           break;
5817         }
5818
5819       if (tmp_column->visible)
5820         total_width += tmp_column->width;
5821     }
5822
5823   gtk_widget_style_get (GTK_WIDGET (tree_view),
5824                         "indent_expanders", &indent_expanders,
5825                         NULL);
5826
5827   if (indent_expanders)
5828     x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
5829
5830   if (x1)
5831     *x1 = x_offset;
5832
5833   if (tmp_column && tmp_column->visible)
5834     {
5835       /* +1 because x2 isn't included in the range. */
5836       if (x2)
5837         *x2 = x_offset + tree_view->priv->expander_size + 1;
5838     }
5839   else
5840     {
5841       /* return an empty range, the expander column is hidden */
5842       if (x2)
5843         *x2 = x_offset;
5844     }
5845 }
5846
5847 static void
5848 gtk_tree_view_build_tree (GtkTreeView *tree_view,
5849                           GtkRBTree   *tree,
5850                           GtkTreeIter *iter,
5851                           gint         depth,
5852                           gboolean     recurse)
5853 {
5854   GtkRBNode *temp = NULL;
5855
5856   do
5857     {
5858       gtk_tree_model_ref_node (tree_view->priv->model, iter);
5859       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
5860       if (recurse)
5861         {
5862           GtkTreeIter child;
5863
5864           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
5865             {
5866               temp->children = _gtk_rbtree_new ();
5867               temp->children->parent_tree = tree;
5868               temp->children->parent_node = temp;
5869               gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
5870             }
5871         }
5872       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
5873         {
5874           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
5875             temp->flags ^= GTK_RBNODE_IS_PARENT;
5876           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
5877         }
5878     }
5879   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
5880 }
5881
5882 /* If height is non-NULL, then we set it to be the new height.  if it's all
5883  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
5884  */
5885 static gboolean
5886 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
5887                                    GtkTreeIter *iter,
5888                                    gint         depth,
5889                                    gint        *height,
5890                                    GtkRBNode   *node)
5891 {
5892   GtkTreeViewColumn *column;
5893   GList *list;
5894   gboolean retval = FALSE;
5895   gint tmpheight;
5896   gint horizontal_separator;
5897
5898   gtk_widget_style_get (GTK_WIDGET (tree_view),
5899                         "horizontal_separator", &horizontal_separator,
5900                         NULL);
5901
5902   if (height)
5903     *height = -1;
5904
5905   for (list = tree_view->priv->columns; list; list = list->next)
5906     {
5907       gint width;
5908       column = list->data;
5909       if (column->dirty == TRUE)
5910         continue;
5911       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
5912         continue;
5913       if (!column->visible)
5914         continue;
5915
5916       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5917                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5918                                                node->children?TRUE:FALSE);
5919
5920       if (height)
5921         {
5922           gtk_tree_view_column_cell_get_size (column,
5923                                               NULL, NULL, NULL,
5924                                               &width, &tmpheight);
5925           *height = MAX (*height, tmpheight);
5926         }
5927       else
5928         {
5929           gtk_tree_view_column_cell_get_size (column,
5930                                               NULL, NULL, NULL,
5931                                               &width, NULL);
5932         }
5933
5934       if (gtk_tree_view_is_expander_column (tree_view, column) &&
5935           TREE_VIEW_DRAW_EXPANDERS (tree_view))
5936         {
5937           if (depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width)
5938             {
5939               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
5940               retval = TRUE;
5941             }
5942         }
5943       else
5944         {
5945           if (horizontal_separator + width > column->requested_width)
5946             {
5947               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
5948               retval = TRUE;
5949             }
5950         }
5951     }
5952
5953   return retval;
5954 }
5955
5956 static void
5957 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
5958                               GtkRBTree   *tree,
5959                               GtkTreeIter *iter,
5960                               gint         depth)
5961 {
5962   GtkRBNode *temp = tree->root;
5963   GtkTreeViewColumn *column;
5964   GList *list;
5965   GtkTreeIter child;
5966   gboolean is_all_dirty;
5967
5968   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
5969
5970   while (temp->left != tree->nil)
5971     temp = temp->left;
5972
5973   do
5974     {
5975       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
5976       is_all_dirty = TRUE;
5977       for (list = tree_view->priv->columns; list; list = list->next)
5978         {
5979           column = list->data;
5980           if (column->dirty == FALSE)
5981             {
5982               is_all_dirty = FALSE;
5983               break;
5984             }
5985         }
5986
5987       if (is_all_dirty)
5988         return;
5989
5990       gtk_tree_view_discover_dirty_iter (tree_view,
5991                                          iter,
5992                                          depth,
5993                                          NULL,
5994                                          temp);
5995       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
5996           temp->children != NULL)
5997         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
5998       temp = _gtk_rbtree_next (tree, temp);
5999     }
6000   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
6001 }
6002
6003
6004 /* Make sure the node is visible vertically */
6005 static void
6006 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
6007                                   GtkRBTree   *tree,
6008                                   GtkRBNode   *node)
6009 {
6010   gint offset;
6011   gint real_height;
6012
6013   /* We process updates because we want to clear old selected items when we scroll.
6014    * if this is removed, we get a "selection streak" at the bottom. */
6015   if (GTK_WIDGET_REALIZED (tree_view))
6016     gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6017
6018   real_height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
6019
6020   offset = _gtk_rbtree_node_find_offset (tree, node);
6021
6022   /* we reverse the order, b/c in the unusual case of the
6023    * node's height being taller then the visible area, we'd rather
6024    * have the node flush to the top
6025    */
6026   if (offset + real_height >
6027       tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
6028     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
6029                               offset + real_height -
6030                               tree_view->priv->vadjustment->page_size);
6031   if (offset < tree_view->priv->vadjustment->value)
6032     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
6033                               offset);
6034
6035 }
6036
6037 static void
6038 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
6039                                     GtkTreeViewColumn *column)
6040 {
6041   if (column == NULL)
6042     return;
6043   if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
6044       (column->button->allocation.x + column->button->allocation.width))
6045     gtk_adjustment_set_value (tree_view->priv->hadjustment,
6046                               column->button->allocation.x + column->button->allocation.width -
6047                               tree_view->priv->hadjustment->page_size);
6048   else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
6049     gtk_adjustment_set_value (tree_view->priv->hadjustment,
6050                               column->button->allocation.x);
6051 }
6052
6053 /* This function could be more efficient.  I'll optimize it if profiling seems
6054  * to imply that it is important */
6055 GtkTreePath *
6056 _gtk_tree_view_find_path (GtkTreeView *tree_view,
6057                           GtkRBTree   *tree,
6058                           GtkRBNode   *node)
6059 {
6060   GtkTreePath *path;
6061   GtkRBTree *tmp_tree;
6062   GtkRBNode *tmp_node, *last;
6063   gint count;
6064
6065   path = gtk_tree_path_new ();
6066
6067   g_return_val_if_fail (node != NULL, path);
6068   g_return_val_if_fail (node != tree->nil, path);
6069
6070   count = 1 + node->left->count;
6071
6072   last = node;
6073   tmp_node = node->parent;
6074   tmp_tree = tree;
6075   while (tmp_tree)
6076     {
6077       while (tmp_node != tmp_tree->nil)
6078         {
6079           if (tmp_node->right == last)
6080             count += 1 + tmp_node->left->count;
6081           last = tmp_node;
6082           tmp_node = tmp_node->parent;
6083         }
6084       gtk_tree_path_prepend_index (path, count - 1);
6085       last = tmp_tree->parent_node;
6086       tmp_tree = tmp_tree->parent_tree;
6087       if (last)
6088         {
6089           count = 1 + last->left->count;
6090           tmp_node = last->parent;
6091         }
6092     }
6093   return path;
6094 }
6095
6096 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
6097  * invalid (ie. points to a node that's not in the tree), *tree and *node are
6098  * both set to NULL.
6099  */
6100 gboolean
6101 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
6102                           GtkTreePath  *path,
6103                           GtkRBTree   **tree,
6104                           GtkRBNode   **node)
6105 {
6106   GtkRBNode *tmpnode = NULL;
6107   GtkRBTree *tmptree = tree_view->priv->tree;
6108   gint *indices = gtk_tree_path_get_indices (path);
6109   gint depth = gtk_tree_path_get_depth (path);
6110   gint i = 0;
6111
6112   *node = NULL;
6113   *tree = NULL;
6114
6115   if (depth == 0 || tmptree == NULL)
6116     return FALSE;
6117   do
6118     {
6119       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
6120       ++i;
6121       if (tmpnode == NULL)
6122         {
6123           *tree = NULL;
6124           *node = NULL;
6125           return FALSE;
6126         }
6127       if (i >= depth)
6128         {
6129           *tree = tmptree;
6130           *node = tmpnode;
6131           return FALSE;
6132         }
6133       *tree = tmptree;
6134       *node = tmpnode;
6135       tmptree = tmpnode->children;
6136       if (tmptree == NULL)
6137         return TRUE;
6138     }
6139   while (1);
6140 }
6141
6142 static gboolean
6143 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
6144                                   GtkTreeViewColumn *column)
6145 {
6146   GList *list;
6147
6148   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
6149     return FALSE;
6150
6151   if (tree_view->priv->expander_column != NULL)
6152     {
6153       if (tree_view->priv->expander_column == column)
6154         return TRUE;
6155       return FALSE;
6156     }
6157   else
6158     {
6159       for (list = tree_view->priv->columns; list; list = list->next)
6160         if (((GtkTreeViewColumn *)list->data)->visible)
6161           break;
6162       if (list && list->data == column)
6163         return TRUE;
6164     }
6165   return FALSE;
6166 }
6167
6168 static void
6169 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
6170                                 guint           keyval,
6171                                 guint           modmask,
6172                                 GtkMovementStep step,
6173                                 gint            count)
6174 {
6175
6176   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
6177                                 "move_cursor", 2,
6178                                 GTK_TYPE_ENUM, step,
6179                                 GTK_TYPE_INT, count);
6180
6181   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
6182                                 "move_cursor", 2,
6183                                 GTK_TYPE_ENUM, step,
6184                                 GTK_TYPE_INT, count);
6185
6186   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
6187    return;
6188
6189   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
6190                                 "move_cursor", 2,
6191                                 GTK_TYPE_ENUM, step,
6192                                 GTK_TYPE_INT, count);
6193
6194   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
6195                                 "move_cursor", 2,
6196                                 GTK_TYPE_ENUM, step,
6197                                 GTK_TYPE_INT, count);
6198 }
6199
6200 static gint
6201 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
6202                                  GtkTreeIter  *iter,
6203                                  GtkRBTree    *tree,
6204                                  GtkRBNode    *node)
6205 {
6206   gint retval = FALSE;
6207   do
6208     {
6209       g_return_val_if_fail (node != NULL, FALSE);
6210
6211       if (node->children)
6212         {
6213           GtkTreeIter child;
6214           GtkRBTree *new_tree;
6215           GtkRBNode *new_node;
6216
6217           new_tree = node->children;
6218           new_node = new_tree->root;
6219
6220           while (new_node && new_node->left != new_tree->nil)
6221             new_node = new_node->left;
6222
6223           g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE);
6224           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
6225         }
6226
6227       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
6228         retval = TRUE;
6229       gtk_tree_model_unref_node (model, iter);
6230       node = _gtk_rbtree_next (tree, node);
6231     }
6232   while (gtk_tree_model_iter_next (model, iter));
6233
6234   return retval;
6235 }
6236
6237 static gint
6238 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
6239                                               GtkRBTree   *tree)
6240 {
6241   GtkTreeIter iter;
6242   GtkTreePath *path;
6243   GtkRBNode *node;
6244   gint retval;
6245
6246   if (!tree)
6247     return FALSE;
6248
6249   node = tree->root;
6250   while (node && node->left != tree->nil)
6251     node = node->left;
6252
6253   g_return_val_if_fail (node != NULL, FALSE);
6254   path = _gtk_tree_view_find_path (tree_view, tree, node);
6255   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
6256                            &iter, path);
6257   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
6258   gtk_tree_path_free (path);
6259
6260   return retval;
6261 }
6262
6263 static void
6264 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
6265                                     GtkTreeViewColumn *column)
6266 {
6267   GtkTreeViewColumn *left_column;
6268   GtkTreeViewColumn *cur_column = NULL;
6269   GtkTreeViewColumnReorder *reorder;
6270
6271   GList *tmp_list;
6272   gint left;
6273
6274   /* We want to precalculate the motion list such that we know what column slots
6275    * are available.
6276    */
6277   left_column = NULL;
6278
6279   /* First, identify all possible drop spots */
6280   tmp_list = tree_view->priv->columns;
6281
6282   while (tmp_list)
6283     {
6284       g_assert (tmp_list);
6285
6286       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
6287       tmp_list = tmp_list->next;
6288
6289       if (cur_column->visible == FALSE)
6290         continue;
6291
6292       /* If it's not the column moving and func tells us to skip over the column, we continue. */
6293       if (left_column != column && cur_column != column &&
6294           tree_view->priv->column_drop_func &&
6295           ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
6296         {
6297           left_column = cur_column;
6298           continue;
6299         }
6300       reorder = g_new (GtkTreeViewColumnReorder, 1);
6301       reorder->left_column = left_column;
6302       left_column = reorder->right_column = cur_column;
6303
6304       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
6305     }
6306
6307   /* Add the last one */
6308   if (tree_view->priv->column_drop_func == NULL ||
6309       ((left_column != column) &&
6310        (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
6311     {
6312       reorder = g_new (GtkTreeViewColumnReorder, 1);
6313       reorder->left_column = left_column;
6314       reorder->right_column = NULL;
6315       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
6316     }
6317
6318   /* We quickly check to see if it even makes sense to reorder columns. */
6319   /* If there is nothing that can be moved, then we return */
6320
6321   if (tree_view->priv->column_drag_info == NULL)
6322     return;
6323
6324   /* We know there are always 2 slots possbile, as you can always return column. */
6325   /* If that's all there is, return */
6326   if (tree_view->priv->column_drag_info->next->next == NULL &&
6327       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
6328       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
6329     {
6330       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
6331         g_free (tmp_list->data);
6332       g_list_free (tree_view->priv->column_drag_info);
6333       tree_view->priv->column_drag_info = NULL;
6334       return;
6335     }
6336   /* We fill in the ranges for the columns, now that we've isolated them */
6337   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
6338
6339   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
6340     {
6341       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
6342
6343       reorder->left_align = left;
6344       if (tmp_list->next != NULL)
6345         {
6346           g_assert (tmp_list->next->data);
6347           left = reorder->right_align = (reorder->right_column->button->allocation.x +
6348                                          reorder->right_column->button->allocation.width +
6349                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
6350         }
6351       else
6352         {
6353           gint width;
6354
6355           gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
6356           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
6357         }
6358     }
6359 }
6360
6361 void
6362 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
6363                                   GtkTreeViewColumn *column)
6364 {
6365   GdkEvent send_event;
6366   GtkAllocation allocation;
6367   gint x, y, width, height;
6368
6369   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
6370
6371   gtk_tree_view_set_column_drag_info (tree_view, column);
6372
6373   if (tree_view->priv->column_drag_info == NULL)
6374     return;
6375
6376   if (tree_view->priv->drag_window == NULL)
6377     {
6378       GdkWindowAttr attributes;
6379       guint attributes_mask;
6380
6381       attributes.window_type = GDK_WINDOW_CHILD;
6382       attributes.wclass = GDK_INPUT_OUTPUT;
6383       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
6384       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
6385       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
6386       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
6387
6388       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
6389                                                      &attributes,
6390                                                      attributes_mask);
6391       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
6392     }
6393
6394   gdk_pointer_ungrab (GDK_CURRENT_TIME);
6395   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
6396
6397   gtk_grab_remove (column->button);
6398
6399   send_event.crossing.type = GDK_LEAVE_NOTIFY;
6400   send_event.crossing.send_event = TRUE;
6401   send_event.crossing.window = column->button->window;
6402   send_event.crossing.subwindow = NULL;
6403   send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
6404   send_event.crossing.time = GDK_CURRENT_TIME;
6405
6406   gtk_propagate_event (column->button, &send_event);
6407
6408   send_event.button.type = GDK_BUTTON_RELEASE;
6409   send_event.button.window = GDK_ROOT_PARENT ();
6410   send_event.button.send_event = TRUE;
6411   send_event.button.time = GDK_CURRENT_TIME;
6412   send_event.button.x = -1;
6413   send_event.button.y = -1;
6414   send_event.button.axes = NULL;
6415   send_event.button.state = 0;
6416   send_event.button.button = 1;
6417   send_event.button.device = gdk_device_get_core_pointer ();
6418   send_event.button.x_root = 0;
6419   send_event.button.y_root = 0;
6420
6421   gtk_propagate_event (column->button, &send_event);
6422
6423   gdk_window_move_resize (tree_view->priv->drag_window,
6424                           column->button->allocation.x,
6425                           0,
6426                           column->button->allocation.width,
6427                           column->button->allocation.height);
6428
6429   /* Kids, don't try this at home */
6430   g_object_ref (column->button);
6431   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
6432   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
6433   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
6434   g_object_unref (column->button);
6435
6436   tree_view->priv->drag_column_x = column->button->allocation.x;
6437   allocation = column->button->allocation;
6438   allocation.x = 0;
6439   gtk_widget_size_allocate (column->button, &allocation);
6440   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
6441
6442   tree_view->priv->drag_column = column;
6443   gdk_window_show (tree_view->priv->drag_window);
6444
6445   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
6446   gdk_window_get_size (tree_view->priv->header_window, &width, &height);
6447
6448   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6449   while (gtk_events_pending ())
6450     gtk_main_iteration ();
6451
6452   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
6453   gdk_pointer_grab (tree_view->priv->drag_window,
6454                     FALSE,
6455                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
6456                     NULL, NULL, GDK_CURRENT_TIME);
6457   gdk_keyboard_grab (tree_view->priv->drag_window,
6458                      FALSE,
6459                      GDK_CURRENT_TIME);
6460
6461 }
6462
6463 static void
6464 gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
6465                                 GtkRBTree        *tree,
6466                                 GtkRBNode        *node,
6467                                 GdkRectangle     *clip_rect)
6468 {
6469   GdkRectangle rect;
6470
6471   if (!GTK_WIDGET_REALIZED (tree_view))
6472     return;
6473
6474   rect.x = 0;
6475   rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width);
6476
6477   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
6478   rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
6479
6480   if (clip_rect)
6481     {
6482       GdkRectangle new_rect;
6483
6484       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
6485
6486       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
6487     }
6488   else
6489     {
6490       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
6491     }
6492 }
6493
6494 void
6495 _gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
6496                                 GtkRBTree    *tree,
6497                                 GtkRBNode    *node,
6498                                 GdkRectangle *clip_rect)
6499 {
6500   GdkRectangle rect;
6501
6502   if (!GTK_WIDGET_REALIZED (tree_view))
6503     return;
6504
6505   rect.x = 0;
6506   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
6507
6508   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
6509   rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
6510
6511   if (clip_rect)
6512     {
6513       GdkRectangle new_rect;
6514
6515       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
6516
6517       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
6518     }
6519   else
6520     {
6521       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
6522     }
6523 }
6524
6525 static void
6526 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
6527                                GtkTreePath      *path,
6528                                GdkRectangle     *clip_rect)
6529 {
6530   GtkRBTree *tree = NULL;
6531   GtkRBNode *node = NULL;
6532
6533   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6534
6535   if (tree)
6536     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
6537 }
6538
6539 /* x and y are the mouse position
6540  */
6541 static void
6542 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
6543                           GtkRBTree   *tree,
6544                           GtkRBNode   *node,
6545                           gint         x,
6546                           gint         y)
6547 {
6548   GdkRectangle area;
6549   GtkStateType state;
6550   GtkWidget *widget;
6551   gint x_offset = 0;
6552   gint vertical_separator;
6553   gint expander_size;
6554   GtkExpanderStyle expander_style;
6555
6556   gtk_widget_style_get (GTK_WIDGET (tree_view),
6557                         "vertical_separator", &vertical_separator,
6558                         NULL);
6559   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
6560
6561   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
6562     return;
6563
6564   widget = GTK_WIDGET (tree_view);
6565
6566   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL);
6567
6568   area.x = x_offset;
6569   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
6570   area.width = expander_size + 2;
6571   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
6572
6573   if (node == tree_view->priv->button_pressed_node)
6574     {
6575       if (x >= area.x && x <= (area.x + area.width) &&
6576           y >= area.y && y <= (area.y + area.height))
6577         state = GTK_STATE_ACTIVE;
6578       else
6579         state = GTK_STATE_NORMAL;
6580     }
6581   else
6582     {
6583       if (node == tree_view->priv->prelight_node &&
6584           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
6585         state = GTK_STATE_PRELIGHT;
6586       else
6587         state = GTK_STATE_NORMAL;
6588     }
6589
6590   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
6591     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
6592   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
6593     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
6594   else if (node->children != NULL)
6595     expander_style = GTK_EXPANDER_EXPANDED;
6596   else
6597     expander_style = GTK_EXPANDER_COLLAPSED;
6598
6599   gtk_paint_expander (widget->style,
6600                       tree_view->priv->bin_window,
6601                       state,
6602                       &area,
6603                       widget,
6604                       "treeview",
6605                       area.x + area.width / 2,
6606                       area.y + area.height / 2,
6607                       expander_style);
6608 }
6609
6610 static void
6611 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
6612
6613 {
6614   GtkTreePath *cursor_path;
6615
6616   if ((tree_view->priv->tree == NULL) ||
6617       (! GTK_WIDGET_REALIZED (tree_view)))
6618     return;
6619
6620   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
6621   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6622
6623   cursor_path = NULL;
6624   if (tree_view->priv->cursor)
6625     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6626
6627   if (cursor_path == NULL)
6628     {
6629       cursor_path = gtk_tree_path_new_root ();
6630       gtk_tree_row_reference_free (tree_view->priv->cursor);
6631       tree_view->priv->cursor = NULL;
6632
6633       if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
6634         gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
6635       else
6636         gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
6637     }
6638   gtk_tree_path_free (cursor_path);
6639   if (tree_view->priv->focus_column == NULL)
6640     {
6641       GList *list;
6642       for (list = tree_view->priv->columns; list; list = list->next)
6643         {
6644           if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
6645             {
6646               tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
6647               break;
6648             }
6649         }
6650     }
6651 }
6652
6653 static void
6654 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
6655                                    gint         count)
6656 {
6657   GtkRBTree *cursor_tree = NULL;
6658   GtkRBNode *cursor_node = NULL;
6659   GtkRBTree *new_cursor_tree = NULL;
6660   GtkRBNode *new_cursor_node = NULL;
6661   GtkTreePath *cursor_path = NULL;
6662
6663   cursor_path = NULL;
6664   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
6665     /* FIXME: we lost the cursor; should we get the first? */
6666     return;
6667
6668   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6669   _gtk_tree_view_find_node (tree_view, cursor_path,
6670                             &cursor_tree, &cursor_node);
6671   gtk_tree_path_free (cursor_path);
6672
6673   if (cursor_tree == NULL)
6674     /* FIXME: we lost the cursor; should we get the first? */
6675     return;
6676   if (count == -1)
6677     _gtk_rbtree_prev_full (cursor_tree, cursor_node,
6678                            &new_cursor_tree, &new_cursor_node);
6679   else
6680     _gtk_rbtree_next_full (cursor_tree, cursor_node,
6681                            &new_cursor_tree, &new_cursor_node);
6682
6683   if (new_cursor_node)
6684     {
6685       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
6686       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
6687       gtk_tree_path_free (cursor_path);
6688     }
6689   else
6690     {
6691       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6692     }
6693
6694   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6695 }
6696
6697 static void
6698 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
6699                                         gint         count)
6700 {
6701   GtkRBTree *cursor_tree = NULL;
6702   GtkRBNode *cursor_node = NULL;
6703   GtkTreePath *cursor_path = NULL;
6704   gint y;
6705   gint vertical_separator;
6706
6707   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
6708     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6709   else
6710     /* This is sorta weird.  Focus in should give us a cursor */
6711     return;
6712
6713   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
6714   _gtk_tree_view_find_node (tree_view, cursor_path,
6715                             &cursor_tree, &cursor_node);
6716
6717   gtk_tree_path_free (cursor_path);
6718
6719   if (cursor_tree == NULL)
6720     /* FIXME: we lost the cursor.  Should we try to get one? */
6721     return;
6722   g_return_if_fail (cursor_node != NULL);
6723
6724   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
6725   y += count * tree_view->priv->vadjustment->page_size;
6726   if (count > 0)
6727     y -= MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
6728               tree_view->priv->expander_size);
6729   else if (count < 0)
6730     y += MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
6731               tree_view->priv->expander_size);
6732   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
6733
6734   _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
6735   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
6736   g_return_if_fail (cursor_path != NULL);
6737   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
6738   gtk_tree_view_scroll_to_point (tree_view, -1, y);
6739   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6740   gtk_tree_path_free (cursor_path);
6741 }
6742
6743 static void
6744 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
6745                                       gint         count)
6746 {
6747   GtkRBTree *cursor_tree = NULL;
6748   GtkRBNode *cursor_node = NULL;
6749   GtkTreePath *cursor_path = NULL;
6750   GtkTreeViewColumn *column;
6751   GtkTreeIter iter;
6752   GList *list;
6753   gboolean found_column = FALSE;
6754
6755   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
6756     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6757   else
6758     return;
6759
6760   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
6761   if (cursor_tree == NULL)
6762     return;
6763   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
6764     {
6765       gtk_tree_path_free (cursor_path);
6766       return;
6767     }
6768   gtk_tree_path_free (cursor_path);
6769
6770   list = tree_view->priv->columns;
6771   if (tree_view->priv->focus_column)
6772     {
6773       for (list = tree_view->priv->columns; list; list = list->next)
6774         {
6775           if (list->data == tree_view->priv->focus_column)
6776             break;
6777         }
6778     }
6779
6780   while (list)
6781     {
6782       column = list->data;
6783       if (column->visible == FALSE)
6784         goto loop_end;
6785
6786       gtk_tree_view_column_cell_set_cell_data (column,
6787                                                tree_view->priv->model,
6788                                                &iter,
6789                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
6790                                                cursor_node->children?TRUE:FALSE);
6791       if (_gtk_tree_view_column_cell_focus (column, count))
6792         {
6793           tree_view->priv->focus_column = column;
6794           found_column = TRUE;
6795           break;
6796         }
6797     loop_end:
6798       if (count == 1)
6799         list = list->next;
6800       else
6801         list = list->prev;
6802     }
6803
6804   if (found_column)
6805     {
6806       _gtk_tree_view_queue_draw_node (tree_view,
6807                                      cursor_tree,
6808                                      cursor_node,
6809                                      NULL);
6810       g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
6811     }
6812   gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
6813 }
6814
6815 static void
6816 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
6817                                      gint         count)
6818 {
6819   GtkRBTree *cursor_tree;
6820   GtkRBNode *cursor_node;
6821   GtkTreePath *path;
6822
6823   g_return_if_fail (tree_view->priv->tree != NULL);
6824
6825   if (count == -1)
6826     {
6827       cursor_tree = tree_view->priv->tree;
6828       cursor_node = cursor_tree->root;
6829       while (cursor_node && cursor_node->left != cursor_tree->nil)
6830         cursor_node = cursor_node->left;
6831     }
6832   else
6833     {
6834       cursor_tree = tree_view->priv->tree;
6835       cursor_node = cursor_tree->root;
6836       do
6837         {
6838           while (cursor_node && cursor_node->right != cursor_tree->nil)
6839             cursor_node = cursor_node->right;
6840           if (cursor_node->children == NULL)
6841             break;
6842
6843           cursor_tree = cursor_node->children;
6844           cursor_node = cursor_tree->root;
6845         }
6846       while (1);
6847     }
6848
6849   path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
6850   gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
6851   gtk_tree_path_free (path);
6852 }
6853
6854 static void
6855 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
6856 {
6857   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
6858     return;
6859   gtk_tree_selection_select_all (tree_view->priv->selection);
6860 }
6861
6862 static void
6863 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
6864 {
6865   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
6866     return;
6867   gtk_tree_selection_unselect_all (tree_view->priv->selection);
6868 }
6869
6870 static void
6871 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
6872                                       gboolean     start_editing)
6873 {
6874   GtkRBTree *cursor_tree = NULL;
6875   GtkRBNode *cursor_node = NULL;
6876   GtkTreePath *cursor_path = NULL;
6877   GdkModifierType state = 0;
6878   cursor_path = NULL;
6879
6880   if (tree_view->priv->cursor)
6881     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6882
6883   if (cursor_path == NULL)
6884     return;
6885
6886   _gtk_tree_view_find_node (tree_view, cursor_path,
6887                             &cursor_tree, &cursor_node);
6888
6889   if (cursor_tree == NULL)
6890     {
6891       gtk_tree_path_free (cursor_path);
6892       return;
6893     }
6894
6895   gtk_get_current_event_state (&state);
6896
6897   if (! (state & GDK_SHIFT_MASK) &&
6898       start_editing &&
6899       tree_view->priv->focus_column)
6900     {
6901       if (gtk_tree_view_start_editing (tree_view, cursor_path))
6902         {
6903           gtk_tree_path_free (cursor_path);
6904           return;
6905         }
6906     }
6907   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
6908                                             cursor_node,
6909                                             cursor_tree,
6910                                             cursor_path,
6911                                             state);
6912
6913   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6914
6915   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6916   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
6917
6918   if (! (state & GDK_SHIFT_MASK))
6919     gtk_tree_view_row_activated (tree_view, cursor_path, tree_view->priv->focus_column);
6920     
6921   gtk_tree_path_free (cursor_path);
6922 }
6923
6924 static void
6925 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
6926 {
6927   GtkRBTree *cursor_tree = NULL;
6928   GtkRBNode *cursor_node = NULL;
6929   GtkTreePath *cursor_path = NULL;
6930
6931   cursor_path = NULL;
6932   if (tree_view->priv->cursor)
6933     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6934
6935   if (cursor_path == NULL)
6936     return;
6937
6938   _gtk_tree_view_find_node (tree_view, cursor_path,
6939                             &cursor_tree, &cursor_node);
6940   if (cursor_tree == NULL)
6941     {
6942       gtk_tree_path_free (cursor_path);
6943       return;
6944     }
6945
6946   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
6947                                             cursor_node,
6948                                             cursor_tree,
6949                                             cursor_path,
6950                                             GDK_CONTROL_MASK);
6951
6952   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6953
6954   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6955   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6956   gtk_tree_path_free (cursor_path);
6957 }
6958
6959
6960
6961 static void
6962 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
6963                                                gboolean     logical,
6964                                                gboolean     expand,
6965                                                gboolean     open_all)
6966 {
6967   GtkTreePath *cursor_path = NULL;
6968   GtkRBTree *tree;
6969   GtkRBNode *node;
6970
6971   cursor_path = NULL;
6972   if (tree_view->priv->cursor)
6973     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6974
6975   if (cursor_path == NULL)
6976     return;
6977
6978   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
6979     return;
6980   
6981   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6982   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6983
6984   if (expand)
6985     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
6986   else
6987     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
6988
6989   gtk_tree_path_free (cursor_path);
6990 }
6991
6992 static void
6993 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
6994 {
6995   GtkRBTree *cursor_tree = NULL;
6996   GtkRBNode *cursor_node = NULL;
6997   GtkTreePath *cursor_path = NULL;
6998
6999   cursor_path = NULL;
7000   if (tree_view->priv->cursor)
7001     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7002
7003   if (cursor_path == NULL)
7004     return;
7005
7006   _gtk_tree_view_find_node (tree_view, cursor_path,
7007                             &cursor_tree, &cursor_node);
7008   if (cursor_tree == NULL)
7009     {
7010       gtk_tree_path_free (cursor_path);
7011       return;
7012     }
7013
7014   if (cursor_tree->parent_node)
7015     {
7016       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7017       cursor_node = cursor_tree->parent_node;
7018       cursor_tree = cursor_tree->parent_tree;
7019
7020       gtk_tree_path_up (cursor_path);
7021       gtk_tree_row_reference_free (tree_view->priv->cursor);
7022       tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
7023       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7024                                                 cursor_node,
7025                                                 cursor_tree,
7026                                                 cursor_path,
7027                                                 0);
7028     }
7029
7030   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
7031
7032   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
7033   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7034   gtk_tree_path_free (cursor_path);
7035 }
7036
7037 static void
7038 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
7039 {
7040   GtkWidget *window;
7041   GtkWidget *entry;
7042   GtkWidget *search_dialog;
7043   GdkEventFocus focus_event;
7044
7045   if (tree_view->priv->enable_search == FALSE ||
7046       tree_view->priv->search_column < 0)
7047     return;
7048
7049   search_dialog = g_object_get_data (G_OBJECT (tree_view),
7050                                      GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
7051   if (search_dialog)
7052     return;
7053
7054   /* set up window */
7055   window = gtk_window_new (GTK_WINDOW_POPUP);
7056   gtk_window_set_title (GTK_WINDOW (window), "search dialog");
7057   gtk_container_set_border_width (GTK_CONTAINER (window), 3);
7058   gtk_window_set_modal (GTK_WINDOW (window), TRUE);
7059   g_signal_connect (G_OBJECT (window), "delete_event",
7060                     G_CALLBACK (gtk_tree_view_search_delete_event),
7061                     tree_view);
7062   g_signal_connect (G_OBJECT (window), "key_press_event",
7063                     G_CALLBACK (gtk_tree_view_search_key_press_event),
7064                     tree_view);
7065   g_signal_connect (G_OBJECT (window), "button_press_event",
7066                     G_CALLBACK (gtk_tree_view_search_button_press_event),
7067                     tree_view);
7068
7069   /* add entry */
7070   entry = gtk_entry_new ();
7071   gtk_widget_show (entry);
7072   g_signal_connect (G_OBJECT (entry), "changed",
7073                     G_CALLBACK (gtk_tree_view_search_init), tree_view);
7074   g_signal_connect (G_OBJECT (entry), "populate_popup",
7075                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
7076                     tree_view);
7077   gtk_container_add (GTK_CONTAINER (window), entry);
7078
7079   /* done, show it */
7080   tree_view->priv->search_dialog_position_func (tree_view, window);
7081   gtk_widget_show_all (window);
7082   gtk_widget_grab_focus (entry);
7083
7084   /* send focus-in event */
7085   focus_event.type = GDK_FOCUS_CHANGE;
7086   focus_event.in = TRUE;
7087   gtk_widget_event (entry, (GdkEvent *) &focus_event);
7088
7089   /* position window */
7090
7091   /* yes, we point to the entry's private text thing here, a bit evil */
7092   g_object_set_data (G_OBJECT (window), "gtk-tree-view-text",
7093                      (gchar *) gtk_entry_get_text (GTK_ENTRY (entry)));
7094   g_object_set_data (G_OBJECT (tree_view),
7095                      GTK_TREE_VIEW_SEARCH_DIALOG_KEY, window);
7096
7097   /* search first matching iter */
7098   gtk_tree_view_search_init (entry, tree_view);
7099 }
7100
7101 static void
7102 gtk_tree_view_real_focus_column_header (GtkTreeView *tree_view)
7103 {
7104   if (!tree_view->priv->focus_column)
7105     return;
7106
7107   gtk_widget_grab_focus (tree_view->priv->focus_column->button);
7108 }
7109
7110 /* this function returns the new width of the column being resized given
7111  * the column and x position of the cursor; the x cursor position is passed
7112  * in as a pointer and automagicly corrected if it's beyond min/max limits
7113  */
7114 static gint
7115 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
7116                                 gint       i,
7117                                 gint      *x)
7118 {
7119   GtkTreeViewColumn *column;
7120   gint width;
7121
7122   /* first translate the x position from widget->window
7123    * to clist->clist_window
7124    */
7125
7126   column = g_list_nth (tree_view->priv->columns, i)->data;
7127   width = *x - column->button->allocation.x;
7128
7129   /* Clamp down the value */
7130   if (column->min_width == -1)
7131     width = MAX (column->button->requisition.width,
7132                  width);
7133   else
7134     width = MAX (column->min_width,
7135                  width);
7136   if (column->max_width != -1)
7137     width = MIN (width, column->max_width != -1);
7138   *x = column->button->allocation.x + width;
7139
7140   return width;
7141 }
7142
7143
7144 /* Callbacks */
7145 static void
7146 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
7147                                   GtkTreeView   *tree_view)
7148 {
7149   if (GTK_WIDGET_REALIZED (tree_view))
7150     {
7151       gint dy;
7152         
7153       gdk_window_move (tree_view->priv->bin_window,
7154                        - tree_view->priv->hadjustment->value,
7155                        TREE_VIEW_HEADER_HEIGHT (tree_view));
7156       gdk_window_move (tree_view->priv->header_window,
7157                        - tree_view->priv->hadjustment->value,
7158                        0);
7159       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
7160       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
7161
7162       /* update our dy and top_row */
7163       tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
7164       gtk_tree_view_dy_to_top_row (tree_view);
7165       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
7166       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
7167     }
7168 }
7169
7170 \f
7171
7172 /* Public methods
7173  */
7174
7175 /**
7176  * gtk_tree_view_new:
7177  *
7178  * Creates a new #GtkTreeView widget.
7179  *
7180  * Return value: A newly created #GtkTreeView widget.
7181  **/
7182 GtkWidget *
7183 gtk_tree_view_new (void)
7184 {
7185   GtkTreeView *tree_view;
7186
7187   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
7188
7189   return GTK_WIDGET (tree_view);
7190 }
7191
7192 /**
7193  * gtk_tree_view_new_with_model:
7194  * @model: the model.
7195  *
7196  * Creates a new #GtkTreeView widget with the model initialized to @model.
7197  *
7198  * Return value: A newly created #GtkTreeView widget.
7199  **/
7200 GtkWidget *
7201 gtk_tree_view_new_with_model (GtkTreeModel *model)
7202 {
7203   GtkTreeView *tree_view;
7204
7205   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
7206   gtk_tree_view_set_model (tree_view, model);
7207
7208   return GTK_WIDGET (tree_view);
7209 }
7210
7211 /* Public Accessors
7212  */
7213
7214 /**
7215  * gtk_tree_view_get_model:
7216  * @tree_view: a #GtkTreeView
7217  *
7218  * Returns the model the the #GtkTreeView is based on.  Returns %NULL if the
7219  * model is unset.
7220  *
7221  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
7222  **/
7223 GtkTreeModel *
7224 gtk_tree_view_get_model (GtkTreeView *tree_view)
7225 {
7226   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7227
7228   return tree_view->priv->model;
7229 }
7230
7231 /**
7232  * gtk_tree_view_set_model:
7233  * @tree_view: A #GtkTreeNode.
7234  * @model: The model.
7235  *
7236  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
7237  * set, it will remove it before setting the new model.  If @model is %NULL, then
7238  * it will unset the old model.
7239  **/
7240 void
7241 gtk_tree_view_set_model (GtkTreeView  *tree_view,
7242                          GtkTreeModel *model)
7243 {
7244   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7245
7246   if (model == tree_view->priv->model)
7247     return;
7248
7249   if (tree_view->priv->model)
7250     {
7251       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
7252
7253       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7254                                             gtk_tree_view_row_changed, tree_view);
7255       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7256                                             gtk_tree_view_row_inserted, tree_view);
7257       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7258                                             gtk_tree_view_row_has_child_toggled, tree_view);
7259       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7260                                             gtk_tree_view_row_deleted, tree_view);
7261       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7262                                             gtk_tree_view_rows_reordered, tree_view);
7263       if (tree_view->priv->tree)
7264         {
7265           _gtk_rbtree_free (tree_view->priv->tree);
7266           tree_view->priv->tree = NULL;
7267         }
7268
7269       tree_view->priv->prelight_node = NULL;
7270       tree_view->priv->prelight_tree = NULL;
7271       tree_view->priv->button_pressed_node = NULL;
7272       tree_view->priv->button_pressed_tree = NULL;
7273
7274       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
7275       tree_view->priv->drag_dest_row = NULL;
7276       gtk_tree_row_reference_free (tree_view->priv->cursor);
7277       tree_view->priv->cursor = NULL;
7278       gtk_tree_row_reference_free (tree_view->priv->anchor);
7279       tree_view->priv->anchor = NULL;
7280
7281       g_object_unref (tree_view->priv->model);
7282       tree_view->priv->search_column = -1;
7283       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
7284     }
7285
7286   tree_view->priv->model = model;
7287
7288
7289   if (tree_view->priv->model)
7290     {
7291       gint i;
7292       GtkTreePath *path;
7293       GtkTreeIter iter;
7294
7295
7296       if (tree_view->priv->search_column == -1)
7297         {
7298           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
7299             {
7300               if (gtk_tree_model_get_column_type (model, i) == G_TYPE_STRING)
7301                 {
7302                   tree_view->priv->search_column = i;
7303                   break;
7304                 }
7305             }
7306         }
7307       g_object_ref (tree_view->priv->model);
7308       g_signal_connect (tree_view->priv->model,
7309                         "row_changed",
7310                         G_CALLBACK (gtk_tree_view_row_changed),
7311                         tree_view);
7312       g_signal_connect (tree_view->priv->model,
7313                         "row_inserted",
7314                         G_CALLBACK (gtk_tree_view_row_inserted),
7315                         tree_view);
7316       g_signal_connect (tree_view->priv->model,
7317                         "row_has_child_toggled",
7318                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
7319                         tree_view);
7320       g_signal_connect (tree_view->priv->model,
7321                         "row_deleted",
7322                         G_CALLBACK (gtk_tree_view_row_deleted),
7323                         tree_view);
7324       g_signal_connect (tree_view->priv->model,
7325                         "rows_reordered",
7326                         G_CALLBACK (gtk_tree_view_rows_reordered),
7327                         tree_view);
7328
7329       path = gtk_tree_path_new_root ();
7330       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
7331         {
7332           tree_view->priv->tree = _gtk_rbtree_new ();
7333           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
7334         }
7335       gtk_tree_path_free (path);
7336
7337       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
7338       install_presize_handler (tree_view);
7339     }
7340
7341   g_object_notify (G_OBJECT (tree_view), "model");
7342
7343   if (GTK_WIDGET_REALIZED (tree_view))
7344     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7345 }
7346
7347 /**
7348  * gtk_tree_view_get_selection:
7349  * @tree_view: A #GtkTreeView.
7350  *
7351  * Gets the #GtkTreeSelection associated with @tree_view.
7352  *
7353  * Return value: A #GtkTreeSelection object.
7354  **/
7355 GtkTreeSelection *
7356 gtk_tree_view_get_selection (GtkTreeView *tree_view)
7357 {
7358   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7359
7360   return tree_view->priv->selection;
7361 }
7362
7363 /**
7364  * gtk_tree_view_get_hadjustment:
7365  * @tree_view: A #GtkTreeView
7366  *
7367  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
7368  *
7369  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
7370  * used.
7371  **/
7372 GtkAdjustment *
7373 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
7374 {
7375   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7376
7377   if (tree_view->priv->hadjustment == NULL)
7378     gtk_tree_view_set_hadjustment (tree_view, NULL);
7379
7380   return tree_view->priv->hadjustment;
7381 }
7382
7383 /**
7384  * gtk_tree_view_set_hadjustment:
7385  * @tree_view: A #GtkTreeView
7386  * @adjustment: The #GtkAdjustment to set, or %NULL
7387  *
7388  * Sets the #GtkAdjustment for the current horizontal aspect.
7389  **/
7390 void
7391 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
7392                                GtkAdjustment *adjustment)
7393 {
7394   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7395
7396   gtk_tree_view_set_adjustments (tree_view,
7397                                  adjustment,
7398                                  tree_view->priv->vadjustment);
7399
7400   g_object_notify (G_OBJECT (tree_view), "hadjustment");
7401 }
7402
7403 /**
7404  * gtk_tree_view_get_vadjustment:
7405  * @tree_view: A #GtkTreeView
7406  *
7407  * Gets the #GtkAdjustment currently being used for the vertical aspect.
7408  *
7409  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
7410  * used.
7411  **/
7412 GtkAdjustment *
7413 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
7414 {
7415   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7416
7417   if (tree_view->priv->vadjustment == NULL)
7418     gtk_tree_view_set_vadjustment (tree_view, NULL);
7419
7420   return tree_view->priv->vadjustment;
7421 }
7422
7423 /**
7424  * gtk_tree_view_set_vadjustment:
7425  * @tree_view: A #GtkTreeView
7426  * @adjustment: The #GtkAdjustment to set, or %NULL
7427  *
7428  * Sets the #GtkAdjustment for the current vertical aspect.
7429  **/
7430 void
7431 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
7432                                GtkAdjustment *adjustment)
7433 {
7434   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7435
7436   gtk_tree_view_set_adjustments (tree_view,
7437                                  tree_view->priv->hadjustment,
7438                                  adjustment);
7439
7440   g_object_notify (G_OBJECT (tree_view), "vadjustment");
7441 }
7442
7443 /* Column and header operations */
7444
7445 /**
7446  * gtk_tree_view_get_headers_visible:
7447  * @tree_view: A #GtkTreeView.
7448  *
7449  * Returns %TRUE if the headers on the @tree_view are visible.
7450  *
7451  * Return value: Whether the headers are visible or not.
7452  **/
7453 gboolean
7454 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
7455 {
7456   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7457
7458   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7459 }
7460
7461 /**
7462  * gtk_tree_view_set_headers_visible:
7463  * @tree_view: A #GtkTreeView.
7464  * @headers_visible: %TRUE if the headers are visible
7465  *
7466  * Sets the the visibility state of the headers.
7467  **/
7468 void
7469 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
7470                                    gboolean     headers_visible)
7471 {
7472   gint x, y;
7473   GList *list;
7474   GtkTreeViewColumn *column;
7475
7476   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7477
7478   headers_visible = !! headers_visible;
7479
7480   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
7481     return;
7482
7483   if (headers_visible)
7484     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7485   else
7486     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7487
7488   if (GTK_WIDGET_REALIZED (tree_view))
7489     {
7490       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
7491       if (headers_visible)
7492         {
7493           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));
7494
7495           if (GTK_WIDGET_MAPPED (tree_view))
7496             gtk_tree_view_map_buttons (tree_view);
7497         }
7498       else
7499         {
7500           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
7501
7502           for (list = tree_view->priv->columns; list; list = list->next)
7503             {
7504               column = list->data;
7505               gtk_widget_unmap (column->button);
7506             }
7507           gdk_window_hide (tree_view->priv->header_window);
7508         }
7509     }
7510
7511   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7512   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
7513   tree_view->priv->vadjustment->lower = 0;
7514   tree_view->priv->vadjustment->upper = tree_view->priv->height;
7515   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
7516
7517   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7518
7519   g_object_notify (G_OBJECT (tree_view), "headers_visible");
7520 }
7521
7522 static void
7523 gtk_tree_view_column_autosize (GtkTreeView *tree_view,
7524                                GtkTreeViewColumn *column)
7525 {
7526   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7527   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7528
7529   if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
7530     return;
7531
7532   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
7533
7534   presize_handler_callback (tree_view);
7535   while (validate_rows_handler (tree_view));
7536
7537   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7538 }
7539
7540 /**
7541  * gtk_tree_view_columns_autosize:
7542  * @tree_view: A #GtkTreeView.
7543  *
7544  * Resizes all columns to their optimal width. Only works after the
7545  * treeview has been realized.
7546  **/
7547 void
7548 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
7549 {
7550   gboolean dirty = FALSE;
7551   GList *list;
7552   GtkTreeViewColumn *column;
7553
7554   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7555
7556   for (list = tree_view->priv->columns; list; list = list->next)
7557     {
7558       column = list->data;
7559       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
7560         continue;
7561       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7562       dirty = TRUE;
7563     }
7564
7565   if (dirty)
7566     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7567 }
7568
7569 /**
7570  * gtk_tree_view_set_headers_clickable:
7571  * @tree_view: A #GtkTreeView.
7572  * @setting: %TRUE if the columns are clickable.
7573  *
7574  * Allow the column title buttons to be clicked.
7575  **/
7576 void
7577 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
7578                                      gboolean   setting)
7579 {
7580   GList *list;
7581
7582   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7583   g_return_if_fail (tree_view->priv->model != NULL);
7584
7585   for (list = tree_view->priv->columns; list; list = list->next)
7586     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
7587
7588   g_object_notify (G_OBJECT (tree_view), "headers_clickable");
7589 }
7590
7591
7592 /**
7593  * gtk_tree_view_set_rules_hint
7594  * @tree_view: a #GtkTreeView
7595  * @setting: %TRUE if the tree requires reading across rows
7596  *
7597  * This function tells GTK+ that the user interface for your
7598  * application requires users to read across tree rows and associate
7599  * cells with one another. By default, GTK+ will then render the tree
7600  * with alternating row colors. Do <emphasis>not</emphasis> use it
7601  * just because you prefer the appearance of the ruled tree; that's a
7602  * question for the theme. Some themes will draw tree rows in
7603  * alternating colors even when rules are turned off, and users who
7604  * prefer that appearance all the time can choose those themes. You
7605  * should call this function only as a <emphasis>semantic</emphasis>
7606  * hint to the theme engine that your tree makes alternating colors
7607  * useful from a functional standpoint (since it has lots of columns,
7608  * generally).
7609  *
7610  **/
7611 void
7612 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
7613                               gboolean      setting)
7614 {
7615   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7616
7617   setting = setting != FALSE;
7618
7619   if (tree_view->priv->has_rules != setting)
7620     {
7621       tree_view->priv->has_rules = setting;
7622       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7623     }
7624
7625   g_object_notify (G_OBJECT (tree_view), "rules_hint");
7626 }
7627
7628 /**
7629  * gtk_tree_view_get_rules_hint
7630  * @tree_view: a #GtkTreeView
7631  *
7632  * Gets the setting set by gtk_tree_view_set_rules_hint().
7633  *
7634  * Return value: %TRUE if rules are useful for the user of this tree
7635  **/
7636 gboolean
7637 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
7638 {
7639   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7640
7641   return tree_view->priv->has_rules;
7642 }
7643
7644 /* Public Column functions
7645  */
7646
7647 /**
7648  * gtk_tree_view_append_column:
7649  * @tree_view: A #GtkTreeView.
7650  * @column: The #GtkTreeViewColumn to add.
7651  *
7652  * Appends @column to the list of columns.
7653  *
7654  * Return value: The number of columns in @tree_view after appending.
7655  **/
7656 gint
7657 gtk_tree_view_append_column (GtkTreeView       *tree_view,
7658                              GtkTreeViewColumn *column)
7659 {
7660   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7661   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7662   g_return_val_if_fail (column->tree_view == NULL, -1);
7663
7664   return gtk_tree_view_insert_column (tree_view, column, -1);
7665 }
7666
7667
7668 /**
7669  * gtk_tree_view_remove_column:
7670  * @tree_view: A #GtkTreeView.
7671  * @column: The #GtkTreeViewColumn to remove.
7672  *
7673  * Removes @column from @tree_view.
7674  *
7675  * Return value: The number of columns in @tree_view after removing.
7676  **/
7677 gint
7678 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
7679                              GtkTreeViewColumn *column)
7680 {
7681   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7682   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7683   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
7684
7685   _gtk_tree_view_column_unset_tree_view (column);
7686
7687   if (tree_view->priv->focus_column == column)
7688     tree_view->priv->focus_column = NULL;
7689
7690   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
7691   tree_view->priv->n_columns--;
7692
7693   if (GTK_WIDGET_REALIZED (tree_view))
7694     {
7695       GList *list;
7696
7697       _gtk_tree_view_column_unrealize_button (column);
7698       for (list = tree_view->priv->columns; list; list = list->next)
7699         {
7700           GtkTreeViewColumn *tmp_column;
7701
7702           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
7703           if (tmp_column->visible)
7704             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
7705         }
7706
7707       if (tree_view->priv->n_columns == 0 &&
7708           gtk_tree_view_get_headers_visible (tree_view))
7709         gdk_window_hide (tree_view->priv->header_window);
7710
7711       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7712     }
7713
7714   g_object_unref (G_OBJECT (column));
7715   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
7716
7717   return tree_view->priv->n_columns;
7718 }
7719
7720 /**
7721  * gtk_tree_view_insert_column:
7722  * @tree_view: A #GtkTreeView.
7723  * @column: The #GtkTreeViewColumn to be inserted.
7724  * @position: The position to insert @column in.
7725  *
7726  * This inserts the @column into the @tree_view at @position.  If @position is
7727  * -1, then the column is inserted at the end.
7728  *
7729  * Return value: The number of columns in @tree_view after insertion.
7730  **/
7731 gint
7732 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
7733                              GtkTreeViewColumn *column,
7734                              gint               position)
7735 {
7736   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7737   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7738   g_return_val_if_fail (column->tree_view == NULL, -1);
7739
7740   g_object_ref (G_OBJECT (column));
7741   gtk_object_sink (GTK_OBJECT (column));
7742
7743   if (tree_view->priv->n_columns == 0 &&
7744       GTK_WIDGET_REALIZED (tree_view) &&
7745       gtk_tree_view_get_headers_visible (tree_view))
7746     {
7747       gdk_window_show (tree_view->priv->header_window);
7748     }
7749
7750   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
7751                                             column, position);
7752   tree_view->priv->n_columns++;
7753
7754   _gtk_tree_view_column_set_tree_view (column, tree_view);
7755
7756   if (GTK_WIDGET_REALIZED (tree_view))
7757     {
7758       GList *list;
7759
7760       _gtk_tree_view_column_realize_button (column);
7761
7762       for (list = tree_view->priv->columns; list; list = list->next)
7763         {
7764           column = GTK_TREE_VIEW_COLUMN (list->data);
7765           if (column->visible)
7766             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7767         }
7768       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7769     }
7770
7771   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
7772
7773   return tree_view->priv->n_columns;
7774 }
7775
7776 /**
7777  * gtk_tree_view_insert_column_with_attributes:
7778  * @tree_view: A #GtkTreeView
7779  * @position: The position to insert the new column in.
7780  * @title: The title to set the header to.
7781  * @cell: The #GtkCellRenderer.
7782  * @Varargs: A %NULL-terminated list of attributes.
7783  *
7784  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
7785  * @position.  If @position is -1, then the newly created column is inserted at
7786  * the end.  The column is initialized with the attributes given.
7787  *
7788  * Return value: The number of columns in @tree_view after insertion.
7789  **/
7790 gint
7791 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
7792                                              gint             position,
7793                                              gchar           *title,
7794                                              GtkCellRenderer *cell,
7795                                              ...)
7796 {
7797   GtkTreeViewColumn *column;
7798   gchar *attribute;
7799   va_list args;
7800   gint column_id;
7801
7802   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7803
7804   column = gtk_tree_view_column_new ();
7805
7806   gtk_tree_view_column_set_title (column, title);
7807   gtk_tree_view_column_pack_start (column, cell, TRUE);
7808
7809   va_start (args, cell);
7810
7811   attribute = va_arg (args, gchar *);
7812
7813   while (attribute != NULL)
7814     {
7815       column_id = va_arg (args, gint);
7816       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
7817       attribute = va_arg (args, gchar *);
7818     }
7819
7820   va_end (args);
7821
7822   gtk_tree_view_insert_column (tree_view, column, position);
7823
7824   return tree_view->priv->n_columns;
7825 }
7826
7827 /**
7828  * gtk_tree_view_insert_column_with_data_func:
7829  * @tree_view: a #GtkTreeView
7830  * @position: Position to insert, -1 for append
7831  * @title: column title
7832  * @cell: cell renderer for column
7833  * @func: function to set attributes of cell renderer
7834  * @data: data for @func
7835  * @dnotify: destroy notifier for @data
7836  *
7837  * Convenience function that inserts a new column into the #GtkTreeView
7838  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
7839  * attributes (normally using data from the model). See also
7840  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
7841  *
7842  * Return value: number of columns in the tree view post-insert
7843  **/
7844 gint
7845 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
7846                                              gint                       position,
7847                                              gchar                     *title,
7848                                              GtkCellRenderer           *cell,
7849                                              GtkTreeCellDataFunc        func,
7850                                              gpointer                   data,
7851                                              GDestroyNotify             dnotify)
7852 {
7853   GtkTreeViewColumn *column;
7854
7855   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7856
7857   column = gtk_tree_view_column_new ();
7858
7859   gtk_tree_view_column_set_title (column, title);
7860   gtk_tree_view_column_pack_start (column, cell, TRUE);
7861   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
7862
7863   gtk_tree_view_insert_column (tree_view, column, position);
7864
7865   return tree_view->priv->n_columns;
7866 }
7867
7868 /**
7869  * gtk_tree_view_get_column:
7870  * @tree_view: A #GtkTreeView.
7871  * @n: The position of the column, counting from 0.
7872  *
7873  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
7874  *
7875  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
7876  * range of columns.
7877  **/
7878 GtkTreeViewColumn *
7879 gtk_tree_view_get_column (GtkTreeView *tree_view,
7880                           gint         n)
7881 {
7882   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7883
7884   if (n < 0 || n >= tree_view->priv->n_columns)
7885     return NULL;
7886
7887   if (tree_view->priv->columns == NULL)
7888     return NULL;
7889
7890   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
7891 }
7892
7893 /**
7894  * gtk_tree_view_get_columns:
7895  * @tree_view: A #GtkTreeView
7896  *
7897  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
7898  * The returned list must be freed with g_list_free ().
7899  *
7900  * Return value: A list of #GtkTreeViewColumn s
7901  **/
7902 GList *
7903 gtk_tree_view_get_columns (GtkTreeView *tree_view)
7904 {
7905   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7906
7907   return g_list_copy (tree_view->priv->columns);
7908 }
7909
7910 /**
7911  * gtk_tree_view_move_column_after:
7912  * @tree_view: A #GtkTreeView
7913  * @column: The #GtkTreeViewColumn to be moved.
7914  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
7915  *
7916  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
7917  * @column is placed in the first position.
7918  **/
7919 void
7920 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
7921                                  GtkTreeViewColumn *column,
7922                                  GtkTreeViewColumn *base_column)
7923 {
7924   GList *column_list_el, *base_el = NULL;
7925
7926   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7927
7928   column_list_el = g_list_find (tree_view->priv->columns, column);
7929   g_return_if_fail (column_list_el != NULL);
7930
7931   if (base_column)
7932     {
7933       base_el = g_list_find (tree_view->priv->columns, base_column);
7934       g_return_if_fail (base_el != NULL);
7935     }
7936
7937   if (column_list_el->prev == base_el)
7938     return;
7939
7940   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
7941   if (base_el == NULL)
7942     {
7943       column_list_el->prev = NULL;
7944       column_list_el->next = tree_view->priv->columns;
7945       if (column_list_el->next)
7946         column_list_el->next->prev = column_list_el;
7947       tree_view->priv->columns = column_list_el;
7948     }
7949   else
7950     {
7951       column_list_el->prev = base_el;
7952       column_list_el->next = base_el->next;
7953       if (column_list_el->next)
7954         column_list_el->next->prev = column_list_el;
7955       base_el->next = column_list_el;
7956     }
7957
7958   if (GTK_WIDGET_REALIZED (tree_view))
7959     {
7960       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7961       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
7962     }
7963
7964   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
7965 }
7966
7967 /**
7968  * gtk_tree_view_set_expander_column:
7969  * @tree_view: A #GtkTreeView
7970  * @column: %NULL, or the column to draw the expander arrow at.
7971  *
7972  * Sets the column to draw the expander arrow at. It must be in @tree_view.  If
7973  * @column is %NULL, then the expander arrow is always at the first visible
7974  * column.
7975  **/
7976 void
7977 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
7978                                    GtkTreeViewColumn *column)
7979 {
7980   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7981   if (column != NULL)
7982     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7983
7984   if (tree_view->priv->expander_column != column)
7985     {
7986       GList *list;
7987
7988       if (column)
7989         {
7990           /* Confirm that column is in tree_view */
7991           for (list = tree_view->priv->columns; list; list = list->next)
7992             if (list->data == column)
7993               break;
7994           g_return_if_fail (list != NULL);
7995         }
7996
7997       tree_view->priv->expander_column = column;
7998       g_object_notify (G_OBJECT (tree_view), "expander_column");
7999     }
8000 }
8001
8002 /**
8003  * gtk_tree_view_get_expander_column:
8004  * @tree_view: A #GtkTreeView
8005  *
8006  * Returns the column that is the current expander column.  This
8007  * column has the expander arrow drawn next to it.
8008  *
8009  * Return value: The expander column.
8010  **/
8011 GtkTreeViewColumn *
8012 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
8013 {
8014   GList *list;
8015
8016   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
8017
8018   for (list = tree_view->priv->columns; list; list = list->next)
8019     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
8020       return (GtkTreeViewColumn *) list->data;
8021   return NULL;
8022 }
8023
8024
8025 /**
8026  * gtk_tree_view_set_column_drag_function:
8027  * @tree_view: A #GtkTreeView.
8028  * @func: A function to determine which columns are reorderable, or %NULL.
8029  * @user_data: User data to be passed to @func, or %NULL
8030  * @destroy: Destroy notifier for @user_data, or %NULL
8031  *
8032  * Sets a user function for determining where a column may be dropped when
8033  * dragged.  This function is called on every column pair in turn at the
8034  * beginning of a column drag to determine where a drop can take place.  The
8035  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
8036  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
8037  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
8038  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
8039  * @tree_view reverts to the default behavior of allowing all columns to be
8040  * dropped everywhere.
8041  **/
8042 void
8043 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
8044                                         GtkTreeViewColumnDropFunc  func,
8045                                         gpointer                   user_data,
8046                                         GtkDestroyNotify           destroy)
8047 {
8048   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8049
8050   if (tree_view->priv->column_drop_func_data_destroy)
8051     (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
8052
8053   tree_view->priv->column_drop_func = func;
8054   tree_view->priv->column_drop_func_data = user_data;
8055   tree_view->priv->column_drop_func_data_destroy = destroy;
8056 }
8057
8058 /**
8059  * gtk_tree_view_scroll_to_point:
8060  * @tree_view: a #GtkTreeView
8061  * @tree_x: X coordinate of new top-left pixel of visible area
8062  * @tree_y: Y coordinate of new top-left pixel of visible area
8063  *
8064  * Scrolls the tree view such that the top-left corner of the visible
8065  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
8066  * in tree window coordinates.  The @tree_view must be realized before
8067  * this function is called.  If it isn't, you probably want to be
8068  * using gtk_tree_view_scroll_to_cell().
8069  **/
8070 void
8071 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
8072                                gint         tree_x,
8073                                gint         tree_y)
8074 {
8075   GtkAdjustment *hadj;
8076   GtkAdjustment *vadj;
8077
8078   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8079   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
8080
8081   hadj = tree_view->priv->hadjustment;
8082   vadj = tree_view->priv->vadjustment;
8083
8084   gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
8085   gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
8086 }
8087
8088 /**
8089  * gtk_tree_view_scroll_to_cell
8090  * @tree_view: A #GtkTreeView.
8091  * @path: The path of the row to move to, or %NULL.
8092  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
8093  * @use_align: whether to use alignment arguments, or %FALSE.
8094  * @row_align: The vertical alignment of the row specified by @path.
8095  * @col_align: The horizontal alignment of the column specified by @column.
8096  *
8097  * Moves the alignments of @tree_view to the position specified by @column and
8098  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
8099  * if @path is %NULL no vertical scrolling occurs.  @row_align determines where
8100  * the row is placed, and @col_align determines where @column is placed.  Both
8101  * are expected to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0
8102  * means right/bottom alignment, 0.5 means center.  If @use_align is %FALSE,
8103  * then the alignment arguments are ignored, and the tree does the minimum
8104  * amount of work to scroll the cell onto the screen.
8105  **/
8106 void
8107 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
8108                               GtkTreePath       *path,
8109                               GtkTreeViewColumn *column,
8110                               gboolean           use_align,
8111                               gfloat             row_align,
8112                               gfloat             col_align)
8113 {
8114   GdkRectangle cell_rect;
8115   GdkRectangle vis_rect;
8116   gint dest_x, dest_y;
8117   gfloat within_margin = 0;
8118
8119   /* FIXME work on unmapped/unrealized trees? maybe implement when
8120    * we do incremental reflow for trees
8121    */
8122
8123   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8124   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
8125   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
8126   g_return_if_fail (path != NULL || column != NULL);
8127
8128   row_align = CLAMP (row_align, 0.0, 1.0);
8129   col_align = CLAMP (col_align, 0.0, 1.0);
8130
8131   if (! GTK_WIDGET_REALIZED (tree_view))
8132     {
8133       if (path)
8134         tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
8135       if (column)
8136         tree_view->priv->scroll_to_column = column;
8137       tree_view->priv->scroll_to_use_align = use_align;
8138       tree_view->priv->scroll_to_row_align = row_align;
8139       tree_view->priv->scroll_to_col_align = col_align;
8140
8141       return;
8142     }
8143
8144   gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
8145   gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
8146
8147   dest_x = vis_rect.x;
8148   dest_y = vis_rect.y;
8149
8150   if (column)
8151     {
8152       if (use_align)
8153         {
8154           dest_x = cell_rect.x + cell_rect.width * row_align - vis_rect.width * row_align;
8155         }
8156       else
8157         {
8158           if (cell_rect.x < vis_rect.x)
8159             dest_x = cell_rect.x - vis_rect.width * within_margin;
8160           else if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
8161             dest_x = cell_rect.x + cell_rect.width - vis_rect.width * (1 - within_margin);
8162         }
8163     }
8164
8165   if (path)
8166     {
8167       if (use_align)
8168         {
8169           dest_y = cell_rect.y + cell_rect.height * col_align - vis_rect.height * col_align;
8170         }
8171       else
8172         {
8173           if (cell_rect.y < vis_rect.y)
8174             dest_y = cell_rect.y - vis_rect.height * within_margin;
8175           else if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
8176             dest_y = cell_rect.y + cell_rect.height - vis_rect.height * (1 - within_margin);
8177         }
8178     }
8179
8180   gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
8181 }
8182
8183
8184 /**
8185  * gtk_tree_view_row_activated:
8186  * @tree_view: A #GtkTreeView
8187  * @path: The #GtkTreePath to be activated.
8188  * @column: The #GtkTreeViewColumn to be activated.
8189  *
8190  * Activates the cell determined by @path and @column.
8191  **/
8192 void
8193 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
8194                              GtkTreePath       *path,
8195                              GtkTreeViewColumn *column)
8196 {
8197   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8198
8199   g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
8200 }
8201
8202
8203 static void
8204 gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
8205                                  GtkRBNode  *node,
8206                                  gpointer  data)
8207 {
8208   GtkTreeView *tree_view = data;
8209
8210   if (node->children)
8211     _gtk_rbtree_traverse (node->children,
8212                           node->children->root,
8213                           G_PRE_ORDER,
8214                           gtk_tree_view_expand_all_helper,
8215                           data);
8216   else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
8217     {
8218       GtkTreePath *path;
8219       GtkTreeIter iter;
8220       GtkTreeIter child;
8221
8222       node->children = _gtk_rbtree_new ();
8223       node->children->parent_tree = tree;
8224       node->children->parent_node = node;
8225       path = _gtk_tree_view_find_path (tree_view, tree, node);
8226       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8227       gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
8228       gtk_tree_view_build_tree (tree_view,
8229                                 node->children,
8230                                 &child,
8231                                 gtk_tree_path_get_depth (path) + 1,
8232                                 TRUE);
8233       gtk_tree_path_free (path);
8234     }
8235 }
8236
8237 /**
8238  * gtk_tree_view_expand_all:
8239  * @tree_view: A #GtkTreeView.
8240  *
8241  * Recursively expands all nodes in the @tree_view.
8242  **/
8243 void
8244 gtk_tree_view_expand_all (GtkTreeView *tree_view)
8245 {
8246   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8247   g_return_if_fail (tree_view->priv->tree != NULL);
8248
8249   _gtk_rbtree_traverse (tree_view->priv->tree,
8250                         tree_view->priv->tree->root,
8251                         G_PRE_ORDER,
8252                         gtk_tree_view_expand_all_helper,
8253                         tree_view);
8254 }
8255
8256 /* Timeout to animate the expander during expands and collapses */
8257 static gboolean
8258 expand_collapse_timeout (gpointer data)
8259 {
8260   GtkTreeView *tree_view = data;
8261   GtkRBNode *node;
8262   GtkRBTree *tree;
8263   gboolean expanding;
8264   gboolean redraw;
8265
8266   GDK_THREADS_ENTER ();
8267
8268   redraw = FALSE;
8269   expanding = TRUE;
8270
8271   node = tree_view->priv->expanded_collapsed_node;
8272   tree = tree_view->priv->expanded_collapsed_tree;
8273
8274   if (node->children == NULL)
8275     expanding = FALSE;
8276
8277   if (expanding)
8278     {
8279       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
8280         {
8281           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8282           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8283
8284           redraw = TRUE;
8285
8286         }
8287       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
8288         {
8289           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8290
8291           redraw = TRUE;
8292         }
8293     }
8294   else
8295     {
8296       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
8297         {
8298           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8299           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8300
8301           redraw = TRUE;
8302         }
8303       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
8304         {
8305           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8306
8307           redraw = TRUE;
8308
8309         }
8310     }
8311
8312   if (redraw)
8313     {
8314       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
8315
8316       GDK_THREADS_LEAVE ();
8317
8318       return TRUE;
8319     }
8320
8321   GDK_THREADS_LEAVE ();
8322
8323   return FALSE;
8324 }
8325
8326 /**
8327  * gtk_tree_view_collapse_all:
8328  * @tree_view: A #GtkTreeView.
8329  *
8330  * Recursively collapses all visible, expanded nodes in @tree_view.
8331  **/
8332 void
8333 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
8334 {
8335   GtkRBTree *tree;
8336   GtkRBNode *node;
8337   GtkTreePath *path;
8338   guint *indices;
8339
8340   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8341   g_return_if_fail (tree_view->priv->tree != NULL);
8342
8343   path = gtk_tree_path_new ();
8344   gtk_tree_path_down (path);
8345   indices = gtk_tree_path_get_indices (path);
8346
8347   tree = tree_view->priv->tree;
8348   node = tree->root;
8349   while (node && node->left != tree->nil)
8350     node = node->left;
8351
8352   while (node)
8353     {
8354       if (node->children)
8355         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
8356       indices[0]++;
8357       node = _gtk_rbtree_next (tree, node);
8358     }
8359
8360   gtk_tree_path_free (path);
8361 }
8362
8363 /* FIXME the bool return values for expand_row and collapse_row are
8364  * not analagous; they should be TRUE if the row had children and
8365  * was not already in the requested state.
8366  */
8367
8368
8369 static gboolean
8370 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
8371                                GtkTreePath *path,
8372                                GtkRBTree   *tree,
8373                                GtkRBNode   *node,
8374                                gboolean     open_all,
8375                                gboolean     animate)
8376 {
8377   GtkTreeIter iter;
8378   GtkTreeIter temp;
8379   gboolean expand;
8380
8381
8382   if (node->children)
8383     return TRUE;
8384   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
8385     return FALSE;
8386
8387   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8388   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
8389     return FALSE;
8390
8391   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
8392
8393   if (expand)
8394     return FALSE;
8395
8396   node->children = _gtk_rbtree_new ();
8397   node->children->parent_tree = tree;
8398   node->children->parent_node = node;
8399
8400   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
8401
8402   gtk_tree_view_build_tree (tree_view,
8403                             node->children,
8404                             &temp,
8405                             gtk_tree_path_get_depth (path) + 1,
8406                             open_all);
8407
8408   if (tree_view->priv->expand_collapse_timeout)
8409     {
8410       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
8411       tree_view->priv->expand_collapse_timeout = 0;
8412     }
8413
8414   if (tree_view->priv->expanded_collapsed_node != NULL)
8415     {
8416       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8417       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8418
8419       tree_view->priv->expanded_collapsed_node = NULL;
8420     }
8421
8422   if (animate)
8423     {
8424       tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
8425       tree_view->priv->expanded_collapsed_node = node;
8426       tree_view->priv->expanded_collapsed_tree = tree;
8427
8428       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8429     }
8430
8431   if (GTK_WIDGET_MAPPED (tree_view))
8432     install_presize_handler (tree_view);
8433
8434   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
8435   return TRUE;
8436 }
8437
8438
8439 /**
8440  * gtk_tree_view_expand_row:
8441  * @tree_view: a #GtkTreeView
8442  * @path: path to a row
8443  * @open_all: whether to recursively expand, or just expand immediate children
8444  *
8445  * Opens the row so its children are visible.
8446  *
8447  * Return value: %TRUE if the row existed and had children
8448  **/
8449 gboolean
8450 gtk_tree_view_expand_row (GtkTreeView *tree_view,
8451                           GtkTreePath *path,
8452                           gboolean     open_all)
8453 {
8454   GtkRBTree *tree;
8455   GtkRBNode *node;
8456
8457   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8458   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
8459   g_return_val_if_fail (path != NULL, FALSE);
8460
8461   if (_gtk_tree_view_find_node (tree_view,
8462                                 path,
8463                                 &tree,
8464                                 &node))
8465     return FALSE;
8466
8467   if (tree != NULL)
8468     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
8469   else
8470     return FALSE;
8471 }
8472
8473 static gboolean
8474 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
8475                                  GtkTreePath *path,
8476                                  GtkRBTree   *tree,
8477                                  GtkRBNode   *node,
8478                                  gboolean     animate)
8479 {
8480   GtkTreeIter iter;
8481   GtkTreeIter children;
8482   gboolean collapse;
8483   gint x, y;
8484   GList *list;
8485
8486   if (node->children == NULL)
8487     return FALSE;
8488
8489   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8490
8491   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
8492
8493   if (collapse)
8494     return FALSE;
8495
8496   /* if the prelighted node is a child of us, we want to unprelight it.  We have
8497    * a chance to prelight the correct node below */
8498
8499   if (tree_view->priv->prelight_tree)
8500     {
8501       GtkRBTree *parent_tree;
8502       GtkRBNode *parent_node;
8503
8504       parent_tree = tree_view->priv->prelight_tree->parent_tree;
8505       parent_node = tree_view->priv->prelight_tree->parent_node;
8506       while (parent_tree)
8507         {
8508           if (parent_tree == tree && parent_node == node)
8509             {
8510               ensure_unprelighted (tree_view);
8511               break;
8512             }
8513           parent_node = parent_tree->parent_node;
8514           parent_tree = parent_tree->parent_tree;
8515         }
8516     }
8517
8518   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
8519
8520   for (list = tree_view->priv->columns; list; list = list->next)
8521     {
8522       GtkTreeViewColumn *column = list->data;
8523
8524       if (column->visible == FALSE)
8525         continue;
8526       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8527         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8528     }
8529
8530   if (tree_view->priv->destroy_count_func)
8531     {
8532       GtkTreePath *child_path;
8533       gint child_count = 0;
8534       child_path = gtk_tree_path_copy (path);
8535       gtk_tree_path_down (child_path);
8536       if (node->children)
8537         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8538       (* tree_view->priv->destroy_count_func) (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
8539       gtk_tree_path_free (child_path);
8540     }
8541
8542   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
8543     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0);
8544   _gtk_rbtree_remove (node->children);
8545
8546   if (tree_view->priv->expand_collapse_timeout)
8547     {
8548       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
8549       tree_view->priv->expand_collapse_timeout = 0;
8550     }
8551   
8552   if (tree_view->priv->expanded_collapsed_node != NULL)
8553     {
8554       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8555       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8556       
8557       tree_view->priv->expanded_collapsed_node = NULL;
8558     }
8559
8560   if (animate)
8561     {
8562       tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
8563       tree_view->priv->expanded_collapsed_node = node;
8564       tree_view->priv->expanded_collapsed_tree = tree;
8565
8566       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8567     }
8568   
8569   if (GTK_WIDGET_MAPPED (tree_view))
8570     {
8571       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8572     }
8573
8574   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8575     {
8576       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8577
8578       if (gtk_tree_path_is_ancestor (path, cursor_path))
8579         {
8580           gtk_tree_row_reference_free (tree_view->priv->cursor);
8581           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
8582                                                                       tree_view->priv->model,
8583                                                                       path);
8584         }
8585       gtk_tree_path_free (cursor_path);
8586     }
8587
8588   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
8589       {
8590       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
8591       if (gtk_tree_path_is_ancestor (path, anchor_path))
8592         {
8593           gtk_tree_row_reference_free (tree_view->priv->anchor);
8594           tree_view->priv->anchor = NULL;
8595         }
8596       gtk_tree_path_free (anchor_path);
8597
8598     }
8599
8600   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
8601
8602   /* now that we've collapsed all rows, we want to try to set the prelight
8603    * again. To do this, we fake a motion event and send it to ourselves. */
8604
8605   if (gdk_window_at_pointer (&x, &y) == tree_view->priv->bin_window)
8606     {
8607       GdkEventMotion event;
8608       event.window = tree_view->priv->bin_window;
8609       event.x = x;
8610       event.y = y;
8611
8612       /* despite the fact this isn't a real event, I'm almost positive it will
8613        * never trigger a drag event.  maybe_drag is the only function that uses
8614        * more than just event.x and event.y. */
8615       gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
8616     }
8617   return TRUE;
8618 }
8619
8620 /**
8621  * gtk_tree_view_collapse_row:
8622  * @tree_view: a #GtkTreeView
8623  * @path: path to a row in the @tree_view
8624  *
8625  * Collapses a row (hides its child rows, if they exist).
8626  *
8627  * Return value: %TRUE if the row was collapsed.
8628  **/
8629 gboolean
8630 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
8631                             GtkTreePath *path)
8632 {
8633   GtkRBTree *tree;
8634   GtkRBNode *node;
8635
8636   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8637   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
8638   g_return_val_if_fail (path != NULL, FALSE);
8639
8640   if (_gtk_tree_view_find_node (tree_view,
8641                                 path,
8642                                 &tree,
8643                                 &node))
8644     return FALSE;
8645
8646   if (tree == NULL || node->children == NULL)
8647     return FALSE;
8648
8649   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
8650 }
8651
8652 static void
8653 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
8654                                         GtkRBTree              *tree,
8655                                         GtkTreePath            *path,
8656                                         GtkTreeViewMappingFunc  func,
8657                                         gpointer                user_data)
8658 {
8659   GtkRBNode *node;
8660
8661   if (tree == NULL || tree->root == NULL)
8662     return;
8663
8664   node = tree->root;
8665
8666   while (node && node->left != tree->nil)
8667     node = node->left;
8668
8669   while (node)
8670     {
8671       if (node->children)
8672         {
8673           gtk_tree_path_down (path);
8674           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
8675           gtk_tree_path_up (path);
8676           (* func) (tree_view, path, user_data);
8677         }
8678       gtk_tree_path_next (path);
8679       node = _gtk_rbtree_next (tree, node);
8680     }
8681 }
8682
8683 /**
8684  * gtk_tree_view_map_expanded_rows:
8685  * @tree_view: A #GtkTreeView
8686  * @func: A function to be called
8687  * @data: User data to be passed to the function.
8688  *
8689  * Calls @func on all expanded rows.
8690  **/
8691 void
8692 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
8693                                  GtkTreeViewMappingFunc  func,
8694                                  gpointer                user_data)
8695 {
8696   GtkTreePath *path;
8697
8698   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8699   g_return_if_fail (func != NULL);
8700
8701   path = gtk_tree_path_new_root ();
8702
8703   gtk_tree_view_map_expanded_rows_helper (tree_view,
8704                                           tree_view->priv->tree,
8705                                           path, func, user_data);
8706
8707   gtk_tree_path_free (path);
8708 }
8709
8710 /**
8711  * gtk_tree_view_row_expanded:
8712  * @tree_view: A #GtkTreeView.
8713  * @path: A #GtkTreePath to test expansion state.
8714  *
8715  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
8716  *
8717  * Return value: %TRUE if #path is expanded.
8718  **/
8719 gboolean
8720 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
8721                             GtkTreePath *path)
8722 {
8723   GtkRBTree *tree;
8724   GtkRBNode *node;
8725
8726   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8727   g_return_val_if_fail (path != NULL, FALSE);
8728
8729   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
8730
8731   if (node == NULL)
8732     return FALSE;
8733
8734   return (node->children != NULL);
8735 }
8736
8737 static GtkTargetEntry row_targets[] = {
8738   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
8739 };
8740
8741
8742 /**
8743  * gtk_tree_view_get_reorderable:
8744  * @tree_view: a #GtkTreeView
8745  *
8746  * Retrieves whether the user can reorder the tree via drag-and-drop. See
8747  * gtk_tree_view_set_reorderable().
8748  *
8749  * Return value: %TRUE if the tree can be reordered.
8750  **/
8751 gboolean
8752 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
8753 {
8754   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8755
8756   return tree_view->priv->reorderable;
8757 }
8758
8759 /**
8760  * gtk_tree_view_set_reorderable:
8761  * @tree_view: A #GtkTreeView.
8762  * @reorderable: %TRUE, if the tree can be reordered.
8763  *
8764  * This function is a convenience function to allow you to reorder models that
8765  * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
8766  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
8767  * the user can reorder the model by dragging and dropping rows.  The
8768  * developer can listen to these changes by connecting to the model's
8769  * signals.
8770  *
8771  * This function does not give you any degree of control over the order -- any
8772  * reorderering is allowed.  If more control is needed, you should probably
8773  * handle drag and drop manually.
8774  **/
8775 void
8776 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
8777                                gboolean     reorderable)
8778 {
8779   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8780
8781   reorderable = reorderable != FALSE;
8782
8783   if (tree_view->priv->reorderable == reorderable)
8784     return;
8785
8786   if (reorderable)
8787     {
8788       gtk_tree_view_enable_model_drag_source (tree_view,
8789                                               GDK_BUTTON1_MASK,
8790                                               row_targets,
8791                                               G_N_ELEMENTS (row_targets),
8792                                               GDK_ACTION_MOVE);
8793       gtk_tree_view_enable_model_drag_dest (tree_view,
8794                                             row_targets,
8795                                             G_N_ELEMENTS (row_targets),
8796                                             GDK_ACTION_MOVE);
8797     }
8798   else
8799     {
8800       gtk_tree_view_unset_rows_drag_source (tree_view);
8801       gtk_tree_view_unset_rows_drag_dest (tree_view);
8802     }
8803
8804   tree_view->priv->reorderable = reorderable;
8805
8806   g_object_notify (G_OBJECT (tree_view), "reorderable");
8807 }
8808
8809 static void
8810 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
8811                                GtkTreePath     *path,
8812                                gboolean         clear_and_select)
8813 {
8814   GtkRBTree *tree = NULL;
8815   GtkRBNode *node = NULL;
8816   GdkModifierType state = 0;
8817
8818   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8819     {
8820       GtkTreePath *cursor_path;
8821       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8822       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
8823       gtk_tree_path_free (cursor_path);
8824     }
8825
8826   gtk_tree_row_reference_free (tree_view->priv->cursor);
8827   gtk_get_current_event_state (&state);
8828
8829   tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
8830                                                               tree_view->priv->model,
8831                                                               path);
8832   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
8833   if (tree != NULL)
8834     {
8835       if (clear_and_select && !((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK))
8836         _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
8837                                                   node, tree, path,
8838                                                   state);
8839       gtk_tree_view_clamp_node_visible (tree_view, tree, node);
8840       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8841     }
8842
8843   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
8844 }
8845
8846 /**
8847  * gtk_tree_view_get_cursor:
8848  * @tree_view: A #GtkTreeView
8849  * @path: A pointer to be filled with the current cursor path, or %NULL
8850  * @focus_column: A pointer to be filled with the current focus column, or %NULL
8851  *
8852  * Fills in @path and @focus_column with the current path and focus column.  If
8853  * the cursor isn't currently set, then *@path will be %NULL.  If no column
8854  * currently has focus, then *@focus_column will be %NULL.
8855  **/
8856 void
8857 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
8858                           GtkTreePath       **path,
8859                           GtkTreeViewColumn **focus_column)
8860 {
8861   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8862
8863   if (path)
8864     {
8865       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8866         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8867       else
8868         *path = NULL;
8869     }
8870
8871   if (focus_column)
8872     {
8873       *focus_column = tree_view->priv->focus_column;
8874     }
8875 }
8876
8877 /**
8878  * gtk_tree_view_set_cursor:
8879  * @tree_view: A #GtkTreeView
8880  * @path: A #GtkTreePath
8881  * @focus_column: A #GtkTreeViewColumn, or %NULL
8882  * @start_editing: %TRUE if the specified cell should start being edited.
8883  *
8884  * Sets the current keyboard focus to be at @path, and selects it.  This is
8885  * useful when you want to focus the user's attention on a particular row.  If
8886  * @column is not %NULL, then focus is given to the column specified by it.
8887  * Additionally, if @column is specified, and @start_editing is %TRUE, then
8888  * editing should be started in the specified cell.  This function is often
8889  * followed by @gtk_widget_grab_focus (@tree_view) in order to give keyboard
8890  * focus to the widget.  Please note that editing can only happen when the
8891  * widget is realized.
8892  **/
8893 void
8894 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
8895                           GtkTreePath       *path,
8896                           GtkTreeViewColumn *focus_column,
8897                           gboolean           start_editing)
8898 {
8899   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8900   g_return_if_fail (path != NULL);
8901   if (focus_column)
8902     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
8903
8904   gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
8905
8906   if (focus_column && focus_column->visible)
8907     {
8908       GList *list;
8909       gboolean column_in_tree = FALSE;
8910
8911       for (list = tree_view->priv->columns; list; list = list->next)
8912         if (list->data == focus_column)
8913           {
8914             column_in_tree = TRUE;
8915             break;
8916           }
8917       g_return_if_fail (column_in_tree);
8918       tree_view->priv->focus_column = focus_column;
8919       if (start_editing)
8920         gtk_tree_view_start_editing (tree_view, path);
8921     }
8922 }
8923
8924
8925 /**
8926  * gtk_tree_view_get_bin_window:
8927  * @tree_view: A #GtkTreeView
8928  * 
8929  * Returns the window that @tree_view renders to.  This is used primarily to
8930  * compare to <literal>event->window</literal> to confirm that the event on
8931  * @tree_view is on the right window.
8932  * 
8933  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
8934  **/
8935 GdkWindow *
8936 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
8937 {
8938   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
8939
8940   return tree_view->priv->bin_window;
8941 }
8942
8943 /**
8944  * gtk_tree_view_get_path_at_pos:
8945  * @tree_view: A #GtkTreeView.
8946  * @x: The x position to be identified.
8947  * @y: The y position to be identified.
8948  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
8949  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
8950  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
8951  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
8952  *
8953  * Finds the path at the point (@x, @y), relative to widget coordinates.  That
8954  * is, @x and @y are relative to an events coordinates. @x and @y must come
8955  * from an event on the @tree_view only where event->window ==
8956  * gtk_tree_view_get_bin (). It is primarily for things like popup menus.
8957  * If @path is non-%NULL, then it will be filled with the #GtkTreePath at that
8958  * point.  This path should be freed with gtk_tree_path_free().  If @column
8959  * is non-%NULL, then it will be filled with the column at that point.
8960  * @cell_x and @cell_y return the coordinates relative to the cell background
8961  * (i.e. the @background_area passed to gtk_cell_renderer_render()).  This
8962  * function is only meaningful if @tree_view is realized.
8963  *
8964  * Return value: %TRUE if a row exists at that coordinate.
8965  **/
8966 gboolean
8967 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
8968                                gint                x,
8969                                gint                y,
8970                                GtkTreePath       **path,
8971                                GtkTreeViewColumn **column,
8972                                gint               *cell_x,
8973                                gint               *cell_y)
8974 {
8975   GtkRBTree *tree;
8976   GtkRBNode *node;
8977   gint y_offset;
8978
8979   g_return_val_if_fail (tree_view != NULL, FALSE);
8980   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
8981
8982   if (path)
8983     *path = NULL;
8984   if (column)
8985     *column = NULL;
8986
8987   if (tree_view->priv->tree == NULL)
8988     return FALSE;
8989
8990   if (x > tree_view->priv->hadjustment->page_size)
8991     return FALSE;
8992
8993   if (x < 0 || y < 0)
8994     return FALSE;
8995
8996   if (column || cell_x)
8997     {
8998       GtkTreeViewColumn *tmp_column;
8999       GtkTreeViewColumn *last_column = NULL;
9000       GList *list;
9001       gint remaining_x = x;
9002       gboolean found = FALSE;
9003
9004       for (list = tree_view->priv->columns; list; list = list->next)
9005         {
9006           tmp_column = list->data;
9007
9008           if (tmp_column->visible == FALSE)
9009             continue;
9010
9011           last_column = tmp_column;
9012           if (remaining_x <= tmp_column->width)
9013             {
9014               found = TRUE;
9015
9016               if (column)
9017                 *column = tmp_column;
9018
9019               if (cell_x)
9020                 *cell_x = remaining_x;
9021
9022               break;
9023             }
9024           remaining_x -= tmp_column->width;
9025         }
9026
9027       if (!found)
9028         {
9029           if (column)
9030             *column = last_column;
9031
9032           if (cell_x)
9033             *cell_x = last_column->width + remaining_x;
9034         }
9035     }
9036
9037   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
9038                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
9039                                       &tree, &node);
9040
9041   if (tree == NULL)
9042     return FALSE;
9043
9044   if (cell_y)
9045     *cell_y = y_offset;
9046
9047   if (path)
9048     *path = _gtk_tree_view_find_path (tree_view, tree, node);
9049
9050   return TRUE;
9051 }
9052
9053
9054 /**
9055  * gtk_tree_view_get_cell_area:
9056  * @tree_view: a #GtkTreeView
9057  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
9058  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
9059  * @rect: rectangle to fill with cell rect
9060  *
9061  * Fills the bounding rectangle in tree window coordinates for the cell at the
9062  * row specified by @path and the column specified by @column.  If @path is
9063  * %NULL, or points to a path not currently displayed, the @y and @height fields
9064  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
9065  * fields will be filled with 0.  The sum of all cell rects does not cover the
9066  * entire tree; there are extra pixels in between rows, for example. The
9067  * returned rectangle is equivalent to the @cell_area passed to
9068  * gtk_cell_renderer_render().  This function is only valid if #tree_view is
9069  * realized.
9070  **/
9071 void
9072 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
9073                              GtkTreePath        *path,
9074                              GtkTreeViewColumn  *column,
9075                              GdkRectangle       *rect)
9076 {
9077   GtkRBTree *tree = NULL;
9078   GtkRBNode *node = NULL;
9079   gint vertical_separator;
9080   gint horizontal_separator;
9081
9082   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9083   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
9084   g_return_if_fail (rect != NULL);
9085   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
9086   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
9087
9088   gtk_widget_style_get (GTK_WIDGET (tree_view),
9089                         "vertical_separator", &vertical_separator,
9090                         "horizontal_separator", &horizontal_separator,
9091                         NULL);
9092
9093   rect->x = 0;
9094   rect->y = 0;
9095   rect->width = 0;
9096   rect->height = 0;
9097
9098   if (column)
9099     {
9100       rect->x = column->button->allocation.x + horizontal_separator/2;
9101       rect->width = column->button->allocation.width - horizontal_separator;
9102     }
9103
9104   if (path)
9105     {
9106       /* Get vertical coords */
9107       if (_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
9108           tree != NULL)
9109         return;
9110
9111       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9112       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
9113
9114       if (gtk_tree_view_is_expander_column (tree_view, column) &&
9115           TREE_VIEW_DRAW_EXPANDERS (tree_view))
9116         {
9117           gint depth = gtk_tree_path_get_depth (path) - 1;
9118
9119           rect->x += depth * tree_view->priv->expander_size;
9120           rect->width -= depth * tree_view->priv->expander_size;
9121           rect->width = MAX (rect->width, 0);
9122         }
9123     }
9124 }
9125
9126 /**
9127  * gtk_tree_view_get_background_area:
9128  * @tree_view: a #GtkTreeView
9129  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
9130  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
9131  * @rect: rectangle to fill with cell background rect
9132  *
9133  * Fills the bounding rectangle in tree window coordinates for the cell at the
9134  * row specified by @path and the column specified by @column.  If @path is
9135  * %NULL, or points to a node not found in the tree, the @y and @height fields of
9136  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
9137  * fields will be filled with 0.  The returned rectangle is equivalent to the
9138  * @background_area passed to gtk_cell_renderer_render().  These background
9139  * areas tile to cover the entire tree window (except for the area used for
9140  * header buttons). Contrast with the @cell_area, returned by
9141  * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
9142  * surrounding borders and the tree expander area.
9143  *
9144  **/
9145 void
9146 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
9147                                    GtkTreePath        *path,
9148                                    GtkTreeViewColumn  *column,
9149                                    GdkRectangle       *rect)
9150 {
9151   GtkRBTree *tree = NULL;
9152   GtkRBNode *node = NULL;
9153
9154   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9155   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
9156   g_return_if_fail (rect != NULL);
9157
9158   rect->x = 0;
9159   rect->y = 0;
9160   rect->width = 0;
9161   rect->height = 0;
9162
9163   if (path)
9164     {
9165       /* Get vertical coords */
9166
9167       if (_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
9168           tree != NULL)
9169         return;
9170
9171       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9172
9173       rect->height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
9174     }
9175
9176   if (column)
9177     {
9178       gint x2 = 0;
9179
9180       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
9181       rect->width = x2 - rect->x;
9182     }
9183 }
9184
9185 /**
9186  * gtk_tree_view_get_visible_rect:
9187  * @tree_view: a #GtkTreeView
9188  * @visible_rect: rectangle to fill
9189  *
9190  * Fills @visible_rect with the currently-visible region of the
9191  * buffer, in tree coordinates. Convert to widget coordinates with
9192  * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
9193  * 0,0 for row 0 of the tree, and cover the entire scrollable area of
9194  * the tree.
9195  **/
9196 void
9197 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
9198                                 GdkRectangle *visible_rect)
9199 {
9200   GtkWidget *widget;
9201
9202   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9203
9204   widget = GTK_WIDGET (tree_view);
9205
9206   if (visible_rect)
9207     {
9208       visible_rect->x = tree_view->priv->hadjustment->value;
9209       visible_rect->y = tree_view->priv->vadjustment->value;
9210       visible_rect->width = widget->allocation.width;
9211       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
9212     }
9213 }
9214
9215 /**
9216  * gtk_tree_view_widget_to_tree_coords:
9217  * @tree_view: a #GtkTreeView
9218  * @wx: widget X coordinate
9219  * @wy: widget Y coordinate
9220  * @tx: return location for tree X coordinate
9221  * @ty: return location for tree Y coordinate
9222  *
9223  * Converts widget coordinates to coordinates for the
9224  * tree window (the full scrollable area of the tree).
9225  *
9226  **/
9227 void
9228 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
9229                                      gint         wx,
9230                                      gint         wy,
9231                                      gint        *tx,
9232                                      gint        *ty)
9233 {
9234   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9235
9236   if (tx)
9237     *tx = wx + tree_view->priv->hadjustment->value;
9238   if (ty)
9239     *ty = wy + tree_view->priv->dy - TREE_VIEW_HEADER_HEIGHT (tree_view);
9240 }
9241
9242 /**
9243  * gtk_tree_view_tree_to_widget_coords:
9244  * @tree_view: a #GtkTreeView
9245  * @tx: tree X coordinate
9246  * @ty: tree Y coordinate
9247  * @wx: return location for widget X coordinate
9248  * @wy: return location for widget Y coordinate
9249  *
9250  * Converts tree coordinates (coordinates in full scrollable area of the tree)
9251  * to widget coordinates.
9252  *
9253  **/
9254 void
9255 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
9256                                      gint         tx,
9257                                      gint         ty,
9258                                      gint        *wx,
9259                                      gint        *wy)
9260 {
9261   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9262
9263   if (wx)
9264     *wx = tx - tree_view->priv->hadjustment->value;
9265   if (wy)
9266     *wy = ty - tree_view->priv->dy + TREE_VIEW_HEADER_HEIGHT (tree_view);
9267 }
9268
9269 static void
9270 unset_reorderable (GtkTreeView *tree_view)
9271 {
9272   if (tree_view->priv->reorderable)
9273     {
9274       tree_view->priv->reorderable = FALSE;
9275       g_object_notify (G_OBJECT (tree_view), "reorderable");
9276     }
9277 }
9278
9279 void
9280 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
9281                                         GdkModifierType           start_button_mask,
9282                                         const GtkTargetEntry     *targets,
9283                                         gint                      n_targets,
9284                                         GdkDragAction             actions)
9285 {
9286   TreeViewDragInfo *di;
9287
9288   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9289
9290   di = ensure_info (tree_view);
9291   clear_source_info (di);
9292
9293   di->start_button_mask = start_button_mask;
9294   di->source_target_list = gtk_target_list_new (targets, n_targets);
9295   di->source_actions = actions;
9296
9297   di->source_set = TRUE;
9298
9299   unset_reorderable (tree_view);
9300 }
9301
9302 void
9303 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
9304                                       const GtkTargetEntry     *targets,
9305                                       gint                      n_targets,
9306                                       GdkDragAction             actions)
9307 {
9308   TreeViewDragInfo *di;
9309
9310   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9311
9312   gtk_drag_dest_set (GTK_WIDGET (tree_view),
9313                      0,
9314                      NULL,
9315                      0,
9316                      actions);
9317
9318   di = ensure_info (tree_view);
9319   clear_dest_info (di);
9320
9321   if (targets)
9322     di->dest_target_list = gtk_target_list_new (targets, n_targets);
9323
9324   di->dest_set = TRUE;
9325
9326   unset_reorderable (tree_view);
9327 }
9328
9329 void
9330 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
9331 {
9332   TreeViewDragInfo *di;
9333
9334   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9335
9336   di = get_info (tree_view);
9337
9338   if (di)
9339     {
9340       if (di->source_set)
9341         {
9342           clear_source_info (di);
9343           di->source_set = FALSE;
9344         }
9345
9346       if (!di->dest_set && !di->source_set)
9347         remove_info (tree_view);
9348     }
9349   
9350   unset_reorderable (tree_view);
9351 }
9352
9353 void
9354 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
9355 {
9356   TreeViewDragInfo *di;
9357
9358   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9359
9360   di = get_info (tree_view);
9361
9362   if (di)
9363     {
9364       if (di->dest_set)
9365         {
9366           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
9367           clear_dest_info (di);
9368           di->dest_set = FALSE;
9369         }
9370
9371       if (!di->dest_set && !di->source_set)
9372         remove_info (tree_view);
9373     }
9374
9375   unset_reorderable (tree_view);
9376 }
9377
9378 void
9379 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
9380                                  GtkTreePath            *path,
9381                                  GtkTreeViewDropPosition pos)
9382 {
9383   GtkTreePath *current_dest;
9384   /* Note; this function is exported to allow a custom DND
9385    * implementation, so it can't touch TreeViewDragInfo
9386    */
9387
9388   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9389
9390   current_dest = NULL;
9391
9392   if (tree_view->priv->drag_dest_row)
9393     current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
9394
9395   if (tree_view->priv->drag_dest_row)
9396     gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
9397
9398   tree_view->priv->drag_dest_pos = pos;
9399
9400   if (path)
9401     {
9402       tree_view->priv->drag_dest_row =
9403         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
9404       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
9405     }
9406   else
9407     tree_view->priv->drag_dest_row = NULL;
9408
9409   if (current_dest)
9410     {
9411       GtkRBTree *tree, *new_tree;
9412       GtkRBNode *node, *new_node;
9413
9414       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
9415       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
9416
9417       if (tree && node)
9418         {
9419           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
9420           if (new_tree && new_node)
9421             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
9422
9423           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
9424           if (new_tree && new_node)
9425             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
9426         }
9427     }
9428 }
9429
9430 void
9431 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
9432                                  GtkTreePath             **path,
9433                                  GtkTreeViewDropPosition  *pos)
9434 {
9435   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9436
9437   if (path)
9438     {
9439       if (tree_view->priv->drag_dest_row)
9440         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
9441       else
9442         *path = NULL;
9443     }
9444
9445   if (pos)
9446     *pos = tree_view->priv->drag_dest_pos;
9447 }
9448
9449 gboolean
9450 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
9451                                    gint                     drag_x,
9452                                    gint                     drag_y,
9453                                    GtkTreePath            **path,
9454                                    GtkTreeViewDropPosition *pos)
9455 {
9456   gint cell_y;
9457   gdouble offset_into_row;
9458   gdouble third;
9459   GdkRectangle cell;
9460   GtkTreeViewColumn *column = NULL;
9461   GtkTreePath *tmp_path = NULL;
9462
9463   /* Note; this function is exported to allow a custom DND
9464    * implementation, so it can't touch TreeViewDragInfo
9465    */
9466
9467   g_return_val_if_fail (tree_view != NULL, FALSE);
9468   g_return_val_if_fail (drag_x >= 0, FALSE);
9469   g_return_val_if_fail (drag_y >= 0, FALSE);
9470   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
9471
9472
9473   if (path)
9474     *path = NULL;
9475
9476   if (tree_view->priv->tree == NULL)
9477     return FALSE;
9478
9479   /* If in the top third of a row, we drop before that row; if
9480    * in the bottom third, drop after that row; if in the middle,
9481    * and the row has children, drop into the row.
9482    */
9483
9484   if (!gtk_tree_view_get_path_at_pos (tree_view,
9485                                       drag_x,
9486                                       drag_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
9487                                       &tmp_path,
9488                                       &column,
9489                                       NULL,
9490                                       &cell_y))
9491     return FALSE;
9492
9493   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
9494                                      &cell);
9495
9496   offset_into_row = cell_y;
9497
9498   if (path)
9499     *path = tmp_path;
9500   else
9501     gtk_tree_path_free (tmp_path);
9502
9503   tmp_path = NULL;
9504
9505   third = cell.height / 3.0;
9506
9507   if (pos)
9508     {
9509       if (offset_into_row < third)
9510         {
9511           *pos = GTK_TREE_VIEW_DROP_BEFORE;
9512         }
9513       else if (offset_into_row < (cell.height / 2.0))
9514         {
9515           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
9516         }
9517       else if (offset_into_row < third * 2)
9518         {
9519           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
9520         }
9521       else
9522         {
9523           *pos = GTK_TREE_VIEW_DROP_AFTER;
9524         }
9525     }
9526
9527   return TRUE;
9528 }
9529
9530
9531
9532 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
9533 /**
9534  * gtk_tree_view_create_row_drag_icon:
9535  * @tree_view: a #GtkTreeView
9536  * @path: a #GtkTreePath in @tree_view
9537  *
9538  * Creates a #GdkPixmap representation of the row at @path.  This image is used
9539  * for a drag icon.
9540  *
9541  * Return value: a newly-allocated pixmap of the drag icon.
9542  **/
9543 GdkPixmap *
9544 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
9545                                     GtkTreePath  *path)
9546 {
9547   GtkTreeIter   iter;
9548   GtkRBTree    *tree;
9549   GtkRBNode    *node;
9550   gint cell_offset;
9551   GList *list;
9552   GdkRectangle background_area;
9553   GdkRectangle expose_area;
9554   GtkWidget *widget;
9555   gint depth;
9556   /* start drawing inside the black outline */
9557   gint x = 1, y = 1;
9558   GdkDrawable *drawable;
9559   gint bin_window_width;
9560
9561   widget = GTK_WIDGET (tree_view);
9562
9563   depth = gtk_tree_path_get_depth (path);
9564
9565   _gtk_tree_view_find_node (tree_view,
9566                             path,
9567                             &tree,
9568                             &node);
9569
9570   if (tree == NULL)
9571     return NULL;
9572
9573   if (!gtk_tree_model_get_iter (tree_view->priv->model,
9574                                 &iter,
9575                                 path))
9576     return NULL;
9577
9578   cell_offset = x;
9579
9580   background_area.y = y;
9581   background_area.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
9582
9583   gdk_drawable_get_size (tree_view->priv->bin_window,
9584                          &bin_window_width, NULL);
9585
9586   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
9587                              bin_window_width + 2,
9588                              background_area.height + 2,
9589                              -1);
9590
9591   expose_area.x = 0;
9592   expose_area.y = 0;
9593   expose_area.width = bin_window_width + 2;
9594   expose_area.height = background_area.height + 2;
9595
9596   gdk_draw_rectangle (drawable,
9597                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
9598                       TRUE,
9599                       0, 0,
9600                       bin_window_width + 2,
9601                       background_area.height + 2);
9602
9603   for (list = tree_view->priv->columns; list; list = list->next)
9604     {
9605       GtkTreeViewColumn *column = list->data;
9606       GdkRectangle cell_area;
9607       gint vertical_separator;
9608
9609       if (!column->visible)
9610         continue;
9611
9612       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
9613                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
9614                                                node->children?TRUE:FALSE);
9615
9616       background_area.x = cell_offset;
9617       background_area.width = column->width;
9618
9619       cell_area = background_area;
9620
9621       gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
9622       cell_area.y += vertical_separator / 2;
9623       cell_area.height -= vertical_separator;
9624
9625       if (gtk_tree_view_is_expander_column (tree_view, column) &&
9626           TREE_VIEW_DRAW_EXPANDERS(tree_view))
9627         {
9628           cell_area.x += depth * tree_view->priv->expander_size;
9629           cell_area.width -= depth * tree_view->priv->expander_size;
9630         }
9631
9632       if (gtk_tree_view_column_cell_is_visible (column))
9633         _gtk_tree_view_column_cell_render (column,
9634                                            drawable,
9635                                            &background_area,
9636                                            &cell_area,
9637                                            &expose_area,
9638                                            0);
9639
9640       cell_offset += column->width;
9641     }
9642
9643   gdk_draw_rectangle (drawable,
9644                       widget->style->black_gc,
9645                       FALSE,
9646                       0, 0,
9647                       bin_window_width + 1,
9648                       background_area.height + 1);
9649
9650   return drawable;
9651 }
9652
9653
9654 /**
9655  * gtk_tree_view_set_destroy_count_func:
9656  * @tree_view: A #GtkTreeView
9657  * @func: Function to be called when a view row is destroyed, or %NULL
9658  * @data: User data to be passed to @func, or %NULL
9659  * @destroy: Destroy notifier for @data, or %NULL
9660  *
9661  * This function should almost never be used.  It is meant for private use by
9662  * ATK for determining the number of visible children that are removed when the
9663  * user collapses a row, or a row is deleted.
9664  **/
9665 void
9666 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
9667                                       GtkTreeDestroyCountFunc  func,
9668                                       gpointer                 data,
9669                                       GtkDestroyNotify         destroy)
9670 {
9671   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9672
9673   if (tree_view->priv->destroy_count_destroy)
9674     (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
9675
9676   tree_view->priv->destroy_count_func = func;
9677   tree_view->priv->destroy_count_data = data;
9678   tree_view->priv->destroy_count_destroy = destroy;
9679 }
9680
9681
9682 /*
9683  * Interactive search
9684  */
9685
9686 /**
9687  * gtk_tree_view_set_enable_search:
9688  * @tree_view: A #GtkTreeView
9689  * @enable_search: %TRUE, if the user can search interactively
9690  *
9691  * If @enable_search is set, then the user can type in text to search through
9692  * the tree interactively.
9693  */
9694 void
9695 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
9696                                  gboolean     enable_search)
9697 {
9698   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9699
9700   enable_search = !!enable_search;
9701   
9702   if (tree_view->priv->enable_search != enable_search)
9703     {
9704        tree_view->priv->enable_search = enable_search;
9705        g_object_notify (G_OBJECT (tree_view), "enable_search");
9706     }
9707 }
9708
9709 /**
9710  * gtk_tree_view_get_enable_search:
9711  * @tree_view: A #GtkTreeView
9712  *
9713  * Returns whether or not the tree allows interactive searching.
9714  *
9715  * Return value: whether or not to let the user search interactively
9716  */
9717 gboolean
9718 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
9719 {
9720   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
9721
9722   return tree_view->priv->enable_search;
9723 }
9724
9725
9726 /**
9727  * gtk_tree_view_get_search_column:
9728  * @tree_view: A #GtkTreeView
9729  *
9730  * Gets the column searched on by the interactive search code.
9731  *
9732  * Return value: the column the interactive search code searches in.
9733  */
9734 gint
9735 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
9736 {
9737   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
9738
9739   return (tree_view->priv->search_column);
9740 }
9741
9742 /**
9743  * gtk_tree_view_set_search_column:
9744  * @tree_view: A #GtkTreeView
9745  * @column: the column to search in
9746  *
9747  * Sets @column as the column where the interactive search code should search
9748  * in.  Additionally, turns on interactive searching.
9749  */
9750 void
9751 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
9752                                  gint         column)
9753 {
9754   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9755   g_return_if_fail (column >= 0);
9756
9757   if (tree_view->priv->search_column == column)
9758     return;
9759
9760   tree_view->priv->search_column = column;
9761   g_object_notify (G_OBJECT (tree_view), "search_column");
9762 }
9763
9764 /**
9765  * gtk_tree_view_search_get_search_equal_func:
9766  * @tree_view: A #GtkTreeView
9767  *
9768  * Returns the compare function currently in use.
9769  *
9770  * Return value: the currently used compare function for the search code.
9771  */
9772
9773 GtkTreeViewSearchEqualFunc
9774 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
9775 {
9776   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
9777
9778   return tree_view->priv->search_equal_func;
9779 }
9780
9781 /**
9782  * gtk_tree_view_set_search_equal_func:
9783  * @tree_view: A #GtkTreeView
9784  * @search_equal_func: the compare function to use during the search
9785  * @search_user_data: user data to pass to @search_equal_func, or %NULL
9786  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
9787  *
9788  * Sets the compare function for the interactive search capabilities.
9789  **/
9790 void
9791 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
9792                                      GtkTreeViewSearchEqualFunc  search_equal_func,
9793                                      gpointer                    search_user_data,
9794                                      GtkDestroyNotify            search_destroy)
9795 {
9796   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9797   g_return_if_fail (search_equal_func !=NULL);
9798
9799   if (tree_view->priv->search_destroy)
9800     (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
9801
9802   tree_view->priv->search_equal_func = search_equal_func;
9803   tree_view->priv->search_user_data = search_user_data;
9804   tree_view->priv->search_destroy = search_destroy;
9805   if (tree_view->priv->search_equal_func == NULL)
9806     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
9807 }
9808
9809 static void
9810 gtk_tree_view_search_dialog_destroy (GtkWidget   *search_dialog,
9811                                      GtkTreeView *tree_view)
9812 {
9813   GtkEntry *entry = (GtkEntry *)(gtk_container_get_children (GTK_CONTAINER (search_dialog)))->data;
9814   gint *selected_iter;
9815
9816   if (tree_view->priv->disable_popdown)
9817     return;
9818
9819   if (entry)
9820     {
9821       GdkEventFocus focus_event;
9822
9823       focus_event.type = GDK_FOCUS_CHANGE;
9824       focus_event.in = FALSE;
9825       gtk_widget_event (GTK_WIDGET (entry), (GdkEvent *) &focus_event);
9826     }
9827
9828   /* remove data from tree_view */
9829   g_object_set_data (G_OBJECT (tree_view), GTK_TREE_VIEW_SEARCH_DIALOG_KEY,
9830                      NULL);
9831
9832   selected_iter = g_object_get_data (G_OBJECT (search_dialog),
9833                                      "gtk-tree-view-selected-iter");
9834   if (selected_iter)
9835     g_free (selected_iter);
9836   g_object_set_data (G_OBJECT (search_dialog), "gtk-tree-view-selected-iter",
9837                      NULL);
9838
9839   gtk_widget_destroy (search_dialog);
9840 }
9841
9842 static void
9843 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
9844                                     GtkWidget   *search_dialog)
9845 {
9846   gint x, y;
9847   gint tree_x, tree_y;
9848   gint tree_width, tree_height;
9849   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
9850   GtkRequisition requisition;
9851
9852   gtk_widget_realize (search_dialog);
9853
9854   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
9855   gdk_window_get_size (tree_window,
9856                        &tree_width,
9857                        &tree_height);
9858   gtk_widget_size_request (search_dialog, &requisition);
9859
9860   if (tree_x + tree_width - requisition.width > gdk_screen_width ())
9861     x = gdk_screen_width () - requisition.width;
9862   else if (tree_x + tree_width - requisition.width < 0)
9863     x = 0;
9864   else
9865     x = tree_x + tree_width - requisition.width;
9866
9867   if (tree_y + tree_height > gdk_screen_height ())
9868     y = gdk_screen_height () - requisition.height;
9869   else if (tree_y + tree_height < 0) /* isn't really possible ... */
9870     y = 0;
9871   else
9872     y = tree_y + tree_height;
9873
9874   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
9875 }
9876
9877 static void
9878 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
9879                                       GtkMenu  *menu,
9880                                       gpointer  data)
9881 {
9882   GtkTreeView *tree_view = (GtkTreeView *)data;
9883
9884   tree_view->priv->disable_popdown = 1;
9885   g_signal_connect (G_OBJECT (menu), "hide",
9886                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
9887 }
9888
9889 static gboolean
9890 gtk_tree_view_real_search_enable_popdown (gpointer data)
9891 {
9892   GtkTreeView *tree_view = (GtkTreeView *)data;
9893
9894   GDK_THREADS_ENTER ();
9895
9896   tree_view->priv->disable_popdown = 0;
9897
9898   GDK_THREADS_LEAVE ();
9899
9900   return FALSE;
9901 }
9902
9903 static void
9904 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
9905                                      gpointer   data)
9906 {
9907   g_timeout_add (200, gtk_tree_view_real_search_enable_popdown, data);
9908 }
9909
9910 static gboolean
9911 gtk_tree_view_search_delete_event (GtkWidget *widget,
9912                                    GdkEventAny *event,
9913                                    GtkTreeView *tree_view)
9914 {
9915   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9916
9917   gtk_tree_view_search_dialog_destroy (widget, tree_view);
9918
9919   return TRUE;
9920 }
9921
9922 static gboolean
9923 gtk_tree_view_search_button_press_event (GtkWidget *widget,
9924                                          GdkEventButton *event,
9925                                          GtkTreeView *tree_view)
9926 {
9927   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9928
9929   gtk_tree_view_search_dialog_destroy (widget, tree_view);
9930
9931   return TRUE;
9932 }
9933
9934 static gboolean
9935 gtk_tree_view_search_key_press_event (GtkWidget *widget,
9936                                       GdkEventKey *event,
9937                                       GtkTreeView *tree_view)
9938 {
9939   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9940   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
9941
9942   /* close window */
9943   if (event->keyval == GDK_Escape ||
9944       event->keyval == GDK_Return ||
9945       event->keyval == GDK_Tab)
9946     {
9947       gtk_tree_view_search_dialog_destroy (widget, tree_view);
9948       return TRUE;
9949     }
9950
9951   /* select previous matching iter */
9952   if (event->keyval == GDK_Up)
9953     {
9954       gtk_tree_view_search_move (widget, tree_view, TRUE);
9955       return TRUE;
9956     }
9957
9958   /* select next matching iter */
9959   if (event->keyval == GDK_Down)
9960     {
9961       gtk_tree_view_search_move (widget, tree_view, FALSE);
9962       return TRUE;
9963     }
9964
9965   return FALSE;
9966 }
9967
9968 static void
9969 gtk_tree_view_search_move (GtkWidget   *window,
9970                            GtkTreeView *tree_view,
9971                            gboolean     up)
9972 {
9973   gboolean ret;
9974   gint *selected_iter;
9975   gint len;
9976   gint count = 0;
9977   gchar *text;
9978   GtkTreeIter iter;
9979   GtkTreeModel *model;
9980   GtkTreeSelection *selection;
9981
9982   text = g_object_get_data (G_OBJECT (window), "gtk-tree-view-text");
9983   selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
9984
9985   g_return_if_fail (text != NULL);
9986
9987   if (!selected_iter || (up && *selected_iter == 1))
9988     return;
9989
9990   len = strlen (text);
9991
9992   if (len < 1)
9993     return;
9994
9995   model = gtk_tree_view_get_model (tree_view);
9996   selection = gtk_tree_view_get_selection (tree_view);
9997
9998   /* search */
9999   gtk_tree_selection_unselect_all (selection);
10000   gtk_tree_model_get_iter_root (model, &iter);
10001
10002   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
10003                                    &count, up?((*selected_iter) - 1):((*selected_iter + 1)));
10004
10005   if (ret)
10006     {
10007       /* found */
10008       *selected_iter += up?(-1):(1);
10009     }
10010   else
10011     {
10012       /* return to old iter */
10013       count = 0;
10014       gtk_tree_model_get_iter_root (model, &iter);
10015       gtk_tree_view_search_iter (model, selection,
10016                                  &iter, text,
10017                                  &count, *selected_iter);
10018     }
10019 }
10020
10021 static gboolean
10022 gtk_tree_view_search_equal_func (GtkTreeModel *model,
10023                                  gint          column,
10024                                  const gchar  *key,
10025                                  GtkTreeIter  *iter,
10026                                  gpointer      search_data)
10027 {
10028   gboolean retval = TRUE;
10029   gchar *normalized_string;
10030   gchar *normalized_key;
10031   gchar *case_normalized_string;
10032   gchar *case_normalized_key;
10033   GValue value = {0,};
10034   gint key_len;
10035
10036   gtk_tree_model_get_value (model, iter, column, &value);
10037   normalized_string = g_utf8_normalize (g_value_get_string (&value), -1, G_NORMALIZE_ALL);
10038   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
10039   case_normalized_string = g_utf8_casefold (normalized_string, -1);
10040   case_normalized_key = g_utf8_casefold (normalized_key, -1);
10041
10042   key_len = strlen (case_normalized_key);
10043
10044   if (!strncmp (case_normalized_key, case_normalized_string, key_len))
10045     retval = FALSE;
10046
10047   g_value_unset (&value);
10048   g_free (normalized_key);
10049   g_free (normalized_string);
10050   g_free (case_normalized_key);
10051   g_free (case_normalized_string);
10052
10053   return retval;
10054 }
10055
10056 static gboolean
10057 gtk_tree_view_search_iter (GtkTreeModel     *model,
10058                            GtkTreeSelection *selection,
10059                            GtkTreeIter      *iter,
10060                            const gchar      *text,
10061                            gint             *count,
10062                            gint              n)
10063 {
10064   GtkRBTree *tree = NULL;
10065   GtkRBNode *node = NULL;
10066   GtkTreePath *path;
10067
10068   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
10069   GtkTreeViewColumn *column =
10070     gtk_tree_view_get_column (tree_view, tree_view->priv->search_column);
10071
10072   path = gtk_tree_model_get_path (model, iter);
10073   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10074
10075   do
10076     {
10077       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
10078         {
10079           (*count)++;
10080           if (*count == n)
10081             {
10082               gtk_tree_selection_select_iter (selection, iter);
10083               gtk_tree_view_scroll_to_cell (tree_view, path, column,
10084                                             TRUE, 0.5, 0.5);
10085               gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
10086
10087               if (path)
10088                 gtk_tree_path_free (path);
10089
10090               return TRUE;
10091             }
10092         }
10093
10094       if (node->children)
10095         {
10096           gboolean has_child;
10097           GtkTreeIter tmp;
10098
10099           tree = node->children;
10100           node = tree->root;
10101
10102           while (node->left != tree->nil)
10103             node = node->left;
10104
10105           tmp = *iter;
10106           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
10107           gtk_tree_path_down (path);
10108
10109           /* sanity check */
10110           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
10111         }
10112       else
10113         {
10114           gboolean done = FALSE;
10115
10116           do
10117             {
10118               node = _gtk_rbtree_next (tree, node);
10119
10120               if (node)
10121                 {
10122                   gboolean has_next;
10123
10124                   has_next = gtk_tree_model_iter_next (model, iter);
10125
10126                   done = TRUE;
10127                   gtk_tree_path_next (path);
10128
10129                   /* sanity check */
10130                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
10131                 }
10132               else
10133                 {
10134                   gboolean has_parent;
10135                   GtkTreeIter tmp_iter = *iter;
10136
10137                   node = tree->parent_node;
10138                   tree = tree->parent_tree;
10139
10140                   if (!tree)
10141                     {
10142                       if (path)
10143                         gtk_tree_path_free (path);
10144
10145                       /* we've run out of tree, done with this func */
10146                       return FALSE;
10147                     }
10148
10149                   has_parent = gtk_tree_model_iter_parent (model,
10150                                                            iter,
10151                                                            &tmp_iter);
10152                   gtk_tree_path_up (path);
10153
10154                   /* sanity check */
10155                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
10156                 }
10157             }
10158           while (!done);
10159         }
10160     }
10161   while (1);
10162
10163   if (path)
10164     gtk_tree_path_free (path);
10165
10166   return FALSE;
10167 }
10168
10169 static void
10170 gtk_tree_view_search_init (GtkWidget   *entry,
10171                            GtkTreeView *tree_view)
10172 {
10173   gint ret;
10174   gint *selected_iter;
10175   gint len;
10176   gint count = 0;
10177   const gchar *text;
10178   GtkWidget *window;
10179   GtkTreeIter iter;
10180   GtkTreeModel *model;
10181   GtkTreeSelection *selection;
10182
10183   g_return_if_fail (GTK_IS_ENTRY (entry));
10184   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10185
10186   window = gtk_widget_get_parent (entry);
10187   text = gtk_entry_get_text (GTK_ENTRY (entry));
10188   len = strlen (text);
10189   model = gtk_tree_view_get_model (tree_view);
10190   selection = gtk_tree_view_get_selection (tree_view);
10191
10192   /* search */
10193   gtk_tree_selection_unselect_all (selection);
10194   selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
10195   if (selected_iter)
10196     g_free (selected_iter);
10197   g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter", NULL);
10198
10199   if (len < 1)
10200     return;
10201
10202   gtk_tree_model_get_iter_root (model, &iter);
10203
10204   ret = gtk_tree_view_search_iter (model, selection,
10205                                    &iter, text,
10206                                    &count, 1);
10207
10208   if (ret)
10209     {
10210       selected_iter = g_malloc (sizeof (int));
10211       *selected_iter = 1;
10212       g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter",
10213                          selected_iter);
10214     }
10215 }
10216
10217 static void
10218 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
10219                              GtkTreeView     *tree_view)
10220 {
10221   if (tree_view->priv->edited_column == NULL)
10222     return;
10223
10224   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
10225   tree_view->priv->edited_column = NULL;
10226
10227   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10228
10229   gtk_container_remove (GTK_CONTAINER (tree_view),
10230                         GTK_WIDGET (cell_editable));
10231 }
10232
10233 static gboolean
10234 gtk_tree_view_start_editing (GtkTreeView *tree_view,
10235                              GtkTreePath *cursor_path)
10236 {
10237   GtkTreeIter iter;
10238   GdkRectangle background_area;
10239   GdkRectangle cell_area;
10240   GtkCellEditable *editable_widget = NULL;
10241   gchar *path_string;
10242   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
10243   gint retval = FALSE;
10244   GtkRBTree *cursor_tree;
10245   GtkRBNode *cursor_node;
10246
10247   g_assert (tree_view->priv->focus_column);
10248
10249   if (! GTK_WIDGET_REALIZED (tree_view))
10250     return FALSE;
10251
10252   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
10253       cursor_node == NULL)
10254     return FALSE;
10255
10256   path_string = gtk_tree_path_to_string (cursor_path);
10257   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
10258   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10259                                            tree_view->priv->model,
10260                                            &iter,
10261                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10262                                            cursor_node->children?TRUE:FALSE);
10263   gtk_tree_view_get_background_area (tree_view,
10264                                      cursor_path,
10265                                      tree_view->priv->focus_column,
10266                                      &background_area);
10267   gtk_tree_view_get_cell_area (tree_view,
10268                                cursor_path,
10269                                tree_view->priv->focus_column,
10270                                &cell_area);
10271   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
10272                                         &editable_widget,
10273                                         NULL,
10274                                         path_string,
10275                                         &background_area,
10276                                         &cell_area,
10277                                         flags))
10278     {
10279       retval = TRUE;
10280       if (editable_widget != NULL)
10281         {
10282           gtk_tree_view_real_start_editing (tree_view,
10283                                             tree_view->priv->focus_column,
10284                                             cursor_path,
10285                                             editable_widget,
10286                                             &cell_area,
10287                                             NULL,
10288                                             flags);
10289         }
10290
10291     }
10292   g_free (path_string);
10293   return retval;
10294 }
10295
10296 static void
10297 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
10298                                   GtkTreeViewColumn *column,
10299                                   GtkTreePath       *path,
10300                                   GtkCellEditable   *cell_editable,
10301                                   GdkRectangle      *cell_area,
10302                                   GdkEvent          *event,
10303                                   guint              flags)
10304 {
10305   tree_view->priv->edited_column = column;
10306   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
10307   gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
10308   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
10309   gtk_tree_view_put (tree_view,
10310                      GTK_WIDGET (cell_editable),
10311                      cell_area->x, cell_area->y, cell_area->width, cell_area->height);
10312   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
10313                                    (GdkEvent *)event);
10314   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
10315   g_signal_connect (cell_editable, "remove_widget", G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
10316 }
10317
10318 static void
10319 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
10320                             gboolean     cancel_editing)
10321 {
10322   if (tree_view->priv->edited_column == NULL)
10323     return;
10324
10325   if (! cancel_editing)
10326     gtk_cell_editable_editing_done (tree_view->priv->edited_column->editable_widget);
10327
10328   gtk_cell_editable_remove_widget (tree_view->priv->edited_column->editable_widget);
10329 }