]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Move destroy signal to GtkWidget
[~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 "config.h"
22 #include <math.h>
23 #include <string.h>
24 #include <gdk/gdkkeysyms.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkprivate.h"
48
49 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
50 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
51 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
52 #define SCROLL_EDGE_SIZE 15
53 #define EXPANDER_EXTRA_PADDING 4
54 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
55 #define AUTO_EXPAND_TIMEOUT 500
56
57 /* The "background" areas of all rows/cells add up to cover the entire tree.
58  * The background includes all inter-row and inter-cell spacing.
59  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
60  * i.e. just the cells, no spacing.
61  */
62
63 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
64 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
65
66 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
67  * vice versa.
68  */
69 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
70 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
71
72 /* This is in bin_window coordinates */
73 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
74 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
75
76 #define ROW_HEIGHT(tree_view,height) \
77   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
78
79
80 typedef struct _GtkTreeViewChild GtkTreeViewChild;
81 struct _GtkTreeViewChild
82 {
83   GtkWidget *widget;
84   gint x;
85   gint y;
86   gint width;
87   gint height;
88 };
89
90
91 typedef struct _TreeViewDragInfo TreeViewDragInfo;
92 struct _TreeViewDragInfo
93 {
94   GdkModifierType start_button_mask;
95   GtkTargetList *_unused_source_target_list;
96   GdkDragAction source_actions;
97
98   GtkTargetList *_unused_dest_target_list;
99
100   guint source_set : 1;
101   guint dest_set : 1;
102 };
103
104
105 /* Signals */
106 enum
107 {
108   ROW_ACTIVATED,
109   TEST_EXPAND_ROW,
110   TEST_COLLAPSE_ROW,
111   ROW_EXPANDED,
112   ROW_COLLAPSED,
113   COLUMNS_CHANGED,
114   CURSOR_CHANGED,
115   MOVE_CURSOR,
116   SELECT_ALL,
117   UNSELECT_ALL,
118   SELECT_CURSOR_ROW,
119   TOGGLE_CURSOR_ROW,
120   EXPAND_COLLAPSE_CURSOR_ROW,
121   SELECT_CURSOR_PARENT,
122   START_INTERACTIVE_SEARCH,
123   LAST_SIGNAL
124 };
125
126 /* Properties */
127 enum {
128   PROP_0,
129   PROP_MODEL,
130   PROP_HADJUSTMENT,
131   PROP_VADJUSTMENT,
132   PROP_HEADERS_VISIBLE,
133   PROP_HEADERS_CLICKABLE,
134   PROP_EXPANDER_COLUMN,
135   PROP_REORDERABLE,
136   PROP_RULES_HINT,
137   PROP_ENABLE_SEARCH,
138   PROP_SEARCH_COLUMN,
139   PROP_FIXED_HEIGHT_MODE,
140   PROP_HOVER_SELECTION,
141   PROP_HOVER_EXPAND,
142   PROP_SHOW_EXPANDERS,
143   PROP_LEVEL_INDENTATION,
144   PROP_RUBBER_BANDING,
145   PROP_ENABLE_GRID_LINES,
146   PROP_ENABLE_TREE_LINES,
147   PROP_TOOLTIP_COLUMN
148 };
149
150 /* object signals */
151 static void     gtk_tree_view_finalize             (GObject          *object);
152 static void     gtk_tree_view_set_property         (GObject         *object,
153                                                     guint            prop_id,
154                                                     const GValue    *value,
155                                                     GParamSpec      *pspec);
156 static void     gtk_tree_view_get_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     GValue          *value,
159                                                     GParamSpec      *pspec);
160
161 /* gtkwidget signals */
162 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
163 static void     gtk_tree_view_realize              (GtkWidget        *widget);
164 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
165 static void     gtk_tree_view_map                  (GtkWidget        *widget);
166 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
167                                                     GtkRequisition   *requisition);
168 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
169                                                     GtkAllocation    *allocation);
170 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
171                                                     cairo_t          *cr);
172 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
173                                                     GdkEventKey      *event);
174 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
175                                                     GdkEventKey      *event);
176 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
177                                                     GdkEventMotion   *event);
178 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
179                                                     GdkEventCrossing *event);
180 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
181                                                     GdkEventCrossing *event);
182 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
183                                                     GdkEventButton   *event);
184 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
185                                                     GdkEventButton   *event);
186 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
187                                                     GdkEventGrabBroken *event);
188 #if 0
189 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
190                                                     GdkEventConfigure *event);
191 #endif
192
193 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
194                                                     GtkWidget        *child);
195 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
196                                                     GdkEventFocus    *event);
197 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
198                                                     GtkDirectionType  direction);
199 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
200 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
201                                                     GtkStyle         *previous_style);
202 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
203                                                     gboolean          was_grabbed);
204 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
205                                                     GtkStateType      previous_state);
206
207 /* container signals */
208 static void     gtk_tree_view_remove               (GtkContainer     *container,
209                                                     GtkWidget        *widget);
210 static void     gtk_tree_view_forall               (GtkContainer     *container,
211                                                     gboolean          include_internals,
212                                                     GtkCallback       callback,
213                                                     gpointer          callback_data);
214
215 /* Source side drag signals */
216 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
217                                             GdkDragContext   *context);
218 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
219                                             GdkDragContext   *context);
220 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
221                                             GdkDragContext   *context,
222                                             GtkSelectionData *selection_data,
223                                             guint             info,
224                                             guint             time);
225 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
226                                             GdkDragContext   *context);
227
228 /* Target side drag signals */
229 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
230                                                   GdkDragContext   *context,
231                                                   guint             time);
232 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
233                                                   GdkDragContext   *context,
234                                                   gint              x,
235                                                   gint              y,
236                                                   guint             time);
237 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
238                                                   GdkDragContext   *context,
239                                                   gint              x,
240                                                   gint              y,
241                                                   guint             time);
242 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
243                                                   GdkDragContext   *context,
244                                                   gint              x,
245                                                   gint              y,
246                                                   GtkSelectionData *selection_data,
247                                                   guint             info,
248                                                   guint             time);
249
250 /* tree_model signals */
251 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
252                                                            GtkAdjustment   *hadj,
253                                                            GtkAdjustment   *vadj);
254 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
255                                                            GtkMovementStep  step,
256                                                            gint             count);
257 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
258 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
259 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
260                                                            gboolean         start_editing);
261 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
262 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
263                                                                gboolean         logical,
264                                                                gboolean         expand,
265                                                                gboolean         open_all);
266 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
267 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
268                                                            GtkTreePath     *path,
269                                                            GtkTreeIter     *iter,
270                                                            gpointer         data);
271 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
272                                                            GtkTreePath     *path,
273                                                            GtkTreeIter     *iter,
274                                                            gpointer         data);
275 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
276                                                            GtkTreePath     *path,
277                                                            GtkTreeIter     *iter,
278                                                            gpointer         data);
279 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
280                                                            GtkTreePath     *path,
281                                                            gpointer         data);
282 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
283                                                            GtkTreePath     *parent,
284                                                            GtkTreeIter     *iter,
285                                                            gint            *new_order,
286                                                            gpointer         data);
287
288 /* Incremental reflow */
289 static gboolean validate_row             (GtkTreeView *tree_view,
290                                           GtkRBTree   *tree,
291                                           GtkRBNode   *node,
292                                           GtkTreeIter *iter,
293                                           GtkTreePath *path);
294 static void     validate_visible_area    (GtkTreeView *tree_view);
295 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
296 static gboolean do_validate_rows         (GtkTreeView *tree_view,
297                                           gboolean     size_request);
298 static gboolean validate_rows            (GtkTreeView *tree_view);
299 static gboolean presize_handler_callback (gpointer     data);
300 static void     install_presize_handler  (GtkTreeView *tree_view);
301 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
302 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
303                                              GtkTreePath *path,
304                                              gint         offset);
305 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
306 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
307 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
308
309 /* Internal functions */
310 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
311                                                               GtkTreeViewColumn  *column);
312 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
313                                                               guint               keyval,
314                                                               guint               modmask,
315                                                               gboolean            add_shifted_binding,
316                                                               GtkMovementStep     step,
317                                                               gint                count);
318 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
319                                                               GtkRBTree          *tree);
320 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
321                                                               GtkTreePath        *path,
322                                                               const GdkRectangle *clip_rect);
323 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
324                                                               GtkRBTree          *tree,
325                                                               GtkRBNode          *node);
326 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
327                                                               cairo_t            *cr,
328                                                               GtkRBTree          *tree,
329                                                               GtkRBNode          *node,
330                                                               gint                x,
331                                                               gint                y);
332 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
333                                                               GtkRBTree          *tree,
334                                                               gint               *x1,
335                                                               gint               *x2);
336 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
337                                                               gint                i,
338                                                               gint               *x);
339 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
340                                                               GtkTreeView        *tree_view);
341 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
342                                                               GtkRBTree          *tree,
343                                                               GtkTreeIter        *iter,
344                                                               gint                depth,
345                                                               gboolean            recurse);
346 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
347                                                               GtkRBTree          *tree,
348                                                               GtkRBNode          *node);
349 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
350                                                               GtkTreeViewColumn  *column,
351                                                               gboolean            focus_to_cell);
352 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
353                                                               GdkEventMotion     *event);
354 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
355 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
356                                                               gint                count);
357 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
358                                                               gint                count);
359 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
360                                                               gint                count);
361 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
362                                                               gint                count);
363 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
364                                                               GtkTreePath        *path,
365                                                               GtkRBTree          *tree,
366                                                               GtkRBNode          *node,
367                                                               gboolean            animate);
368 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
369                                                               GtkTreePath        *path,
370                                                               GtkRBTree          *tree,
371                                                               GtkRBNode          *node,
372                                                               gboolean            open_all,
373                                                               gboolean            animate);
374 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
375                                                               GtkTreePath        *path,
376                                                               gboolean            clear_and_select,
377                                                               gboolean            clamp_node);
378 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
379 static void     column_sizing_notify                         (GObject            *object,
380                                                               GParamSpec         *pspec,
381                                                               gpointer            data);
382 static gboolean expand_collapse_timeout                      (gpointer            data);
383 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
384                                                               GtkRBTree          *tree,
385                                                               GtkRBNode          *node,
386                                                               gboolean            expand);
387 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
388 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
389 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
390 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
391 static void     update_prelight                              (GtkTreeView        *tree_view,
392                                                               int                 x,
393                                                               int                 y);
394
395 /* interactive search */
396 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
397 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
398                                                          GtkTreeView      *tree_view,
399                                                          GdkDevice        *device);
400 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
401                                                          GtkWidget        *search_dialog,
402                                                          gpointer          user_data);
403 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
404                                                          GtkMenu          *menu,
405                                                          gpointer          data);
406 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
407                                                          GtkTreeView      *tree_view);
408 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
409                                                          GtkTreeView      *tree_view);
410 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
411 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
412                                                          gpointer          data);
413 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
414                                                          GdkEventAny      *event,
415                                                          GtkTreeView      *tree_view);
416 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
417                                                          GdkEventButton   *event,
418                                                          GtkTreeView      *tree_view);
419 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
420                                                          GdkEventScroll   *event,
421                                                          GtkTreeView      *tree_view);
422 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
423                                                          GdkEventKey      *event,
424                                                          GtkTreeView      *tree_view);
425 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
426                                                          GtkTreeView      *tree_view,
427                                                          gboolean          up);
428 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
429                                                          gint              column,
430                                                          const gchar      *key,
431                                                          GtkTreeIter      *iter,
432                                                          gpointer          search_data);
433 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
434                                                          GtkTreeSelection *selection,
435                                                          GtkTreeIter      *iter,
436                                                          const gchar      *text,
437                                                          gint             *count,
438                                                          gint              n);
439 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
440                                                          GtkTreeView      *tree_view);
441 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
442                                                          GtkWidget        *child_widget,
443                                                          gint              x,
444                                                          gint              y,
445                                                          gint              width,
446                                                          gint              height);
447 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
448                                                          GtkTreePath      *cursor_path);
449 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
450                                               GtkTreeViewColumn *column,
451                                               GtkTreePath       *path,
452                                               GtkCellEditable   *cell_editable,
453                                               GdkRectangle      *cell_area,
454                                               GdkEvent          *event,
455                                               guint              flags);
456 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
457                                                          gboolean     cancel_editing);
458 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
459                                                              GdkDevice   *device,
460                                                              gboolean     keybinding);
461 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
462 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
463                                                          GtkTreeViewColumn *column,
464                                                          gint               drop_position);
465
466 /* GtkBuildable */
467 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
468                                                             GtkBuilder        *builder,
469                                                             GObject           *child,
470                                                             const gchar       *type);
471 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
472                                                             GtkBuilder        *builder,
473                                                             const gchar       *childname);
474 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
475
476
477 static gboolean scroll_row_timeout                   (gpointer     data);
478 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
479 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
480
481 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
482
483 \f
484
485 /* GType Methods
486  */
487
488 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
489                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
490                                                 gtk_tree_view_buildable_init))
491
492 static void
493 gtk_tree_view_class_init (GtkTreeViewClass *class)
494 {
495   GObjectClass *o_class;
496   GtkWidgetClass *widget_class;
497   GtkContainerClass *container_class;
498   GtkBindingSet *binding_set;
499
500   binding_set = gtk_binding_set_by_class (class);
501
502   o_class = (GObjectClass *) class;
503   widget_class = (GtkWidgetClass *) class;
504   container_class = (GtkContainerClass *) class;
505
506   /* GObject signals */
507   o_class->set_property = gtk_tree_view_set_property;
508   o_class->get_property = gtk_tree_view_get_property;
509   o_class->finalize = gtk_tree_view_finalize;
510
511   /* GtkWidget signals */
512   widget_class->destroy = gtk_tree_view_destroy;
513   widget_class->map = gtk_tree_view_map;
514   widget_class->realize = gtk_tree_view_realize;
515   widget_class->unrealize = gtk_tree_view_unrealize;
516   widget_class->size_request = gtk_tree_view_size_request;
517   widget_class->size_allocate = gtk_tree_view_size_allocate;
518   widget_class->button_press_event = gtk_tree_view_button_press;
519   widget_class->button_release_event = gtk_tree_view_button_release;
520   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
521   /*widget_class->configure_event = gtk_tree_view_configure;*/
522   widget_class->motion_notify_event = gtk_tree_view_motion;
523   widget_class->draw = gtk_tree_view_draw;
524   widget_class->key_press_event = gtk_tree_view_key_press;
525   widget_class->key_release_event = gtk_tree_view_key_release;
526   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
527   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
528   widget_class->focus_out_event = gtk_tree_view_focus_out;
529   widget_class->drag_begin = gtk_tree_view_drag_begin;
530   widget_class->drag_end = gtk_tree_view_drag_end;
531   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
532   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
533   widget_class->drag_leave = gtk_tree_view_drag_leave;
534   widget_class->drag_motion = gtk_tree_view_drag_motion;
535   widget_class->drag_drop = gtk_tree_view_drag_drop;
536   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
537   widget_class->focus = gtk_tree_view_focus;
538   widget_class->grab_focus = gtk_tree_view_grab_focus;
539   widget_class->style_set = gtk_tree_view_style_set;
540   widget_class->grab_notify = gtk_tree_view_grab_notify;
541   widget_class->state_changed = gtk_tree_view_state_changed;
542
543   /* GtkContainer signals */
544   container_class->remove = gtk_tree_view_remove;
545   container_class->forall = gtk_tree_view_forall;
546   container_class->set_focus_child = gtk_tree_view_set_focus_child;
547
548   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
549   class->move_cursor = gtk_tree_view_real_move_cursor;
550   class->select_all = gtk_tree_view_real_select_all;
551   class->unselect_all = gtk_tree_view_real_unselect_all;
552   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
553   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
554   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
555   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
556   class->start_interactive_search = gtk_tree_view_start_interactive_search;
557
558   /* Properties */
559
560   g_object_class_install_property (o_class,
561                                    PROP_MODEL,
562                                    g_param_spec_object ("model",
563                                                         P_("TreeView Model"),
564                                                         P_("The model for the tree view"),
565                                                         GTK_TYPE_TREE_MODEL,
566                                                         GTK_PARAM_READWRITE));
567
568   g_object_class_install_property (o_class,
569                                    PROP_HADJUSTMENT,
570                                    g_param_spec_object ("hadjustment",
571                                                         P_("Horizontal Adjustment"),
572                                                         P_("Horizontal Adjustment for the widget"),
573                                                         GTK_TYPE_ADJUSTMENT,
574                                                         GTK_PARAM_READWRITE));
575
576   g_object_class_install_property (o_class,
577                                    PROP_VADJUSTMENT,
578                                    g_param_spec_object ("vadjustment",
579                                                         P_("Vertical Adjustment"),
580                                                         P_("Vertical Adjustment for the widget"),
581                                                         GTK_TYPE_ADJUSTMENT,
582                                                         GTK_PARAM_READWRITE));
583
584   g_object_class_install_property (o_class,
585                                    PROP_HEADERS_VISIBLE,
586                                    g_param_spec_boolean ("headers-visible",
587                                                          P_("Headers Visible"),
588                                                          P_("Show the column header buttons"),
589                                                          TRUE,
590                                                          GTK_PARAM_READWRITE));
591
592   g_object_class_install_property (o_class,
593                                    PROP_HEADERS_CLICKABLE,
594                                    g_param_spec_boolean ("headers-clickable",
595                                                          P_("Headers Clickable"),
596                                                          P_("Column headers respond to click events"),
597                                                          TRUE,
598                                                          GTK_PARAM_READWRITE));
599
600   g_object_class_install_property (o_class,
601                                    PROP_EXPANDER_COLUMN,
602                                    g_param_spec_object ("expander-column",
603                                                         P_("Expander Column"),
604                                                         P_("Set the column for the expander column"),
605                                                         GTK_TYPE_TREE_VIEW_COLUMN,
606                                                         GTK_PARAM_READWRITE));
607
608   g_object_class_install_property (o_class,
609                                    PROP_REORDERABLE,
610                                    g_param_spec_boolean ("reorderable",
611                                                          P_("Reorderable"),
612                                                          P_("View is reorderable"),
613                                                          FALSE,
614                                                          GTK_PARAM_READWRITE));
615
616   g_object_class_install_property (o_class,
617                                    PROP_RULES_HINT,
618                                    g_param_spec_boolean ("rules-hint",
619                                                          P_("Rules Hint"),
620                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
621                                                          FALSE,
622                                                          GTK_PARAM_READWRITE));
623
624     g_object_class_install_property (o_class,
625                                      PROP_ENABLE_SEARCH,
626                                      g_param_spec_boolean ("enable-search",
627                                                            P_("Enable Search"),
628                                                            P_("View allows user to search through columns interactively"),
629                                                            TRUE,
630                                                            GTK_PARAM_READWRITE));
631
632     g_object_class_install_property (o_class,
633                                      PROP_SEARCH_COLUMN,
634                                      g_param_spec_int ("search-column",
635                                                        P_("Search Column"),
636                                                        P_("Model column to search through during interactive search"),
637                                                        -1,
638                                                        G_MAXINT,
639                                                        -1,
640                                                        GTK_PARAM_READWRITE));
641
642     /**
643      * GtkTreeView:fixed-height-mode:
644      *
645      * Setting the ::fixed-height-mode property to %TRUE speeds up 
646      * #GtkTreeView by assuming that all rows have the same height. 
647      * Only enable this option if all rows are the same height.  
648      * Please see gtk_tree_view_set_fixed_height_mode() for more 
649      * information on this option.
650      *
651      * Since: 2.4
652      **/
653     g_object_class_install_property (o_class,
654                                      PROP_FIXED_HEIGHT_MODE,
655                                      g_param_spec_boolean ("fixed-height-mode",
656                                                            P_("Fixed Height Mode"),
657                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
658                                                            FALSE,
659                                                            GTK_PARAM_READWRITE));
660     
661     /**
662      * GtkTreeView:hover-selection:
663      * 
664      * Enables or disables the hover selection mode of @tree_view.
665      * Hover selection makes the selected row follow the pointer.
666      * Currently, this works only for the selection modes 
667      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
668      *
669      * This mode is primarily intended for treeviews in popups, e.g.
670      * in #GtkComboBox or #GtkEntryCompletion.
671      *
672      * Since: 2.6
673      */
674     g_object_class_install_property (o_class,
675                                      PROP_HOVER_SELECTION,
676                                      g_param_spec_boolean ("hover-selection",
677                                                            P_("Hover Selection"),
678                                                            P_("Whether the selection should follow the pointer"),
679                                                            FALSE,
680                                                            GTK_PARAM_READWRITE));
681
682     /**
683      * GtkTreeView:hover-expand:
684      * 
685      * Enables or disables the hover expansion mode of @tree_view.
686      * Hover expansion makes rows expand or collapse if the pointer moves 
687      * over them.
688      *
689      * This mode is primarily intended for treeviews in popups, e.g.
690      * in #GtkComboBox or #GtkEntryCompletion.
691      *
692      * Since: 2.6
693      */
694     g_object_class_install_property (o_class,
695                                      PROP_HOVER_EXPAND,
696                                      g_param_spec_boolean ("hover-expand",
697                                                            P_("Hover Expand"),
698                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
699                                                            FALSE,
700                                                            GTK_PARAM_READWRITE));
701
702     /**
703      * GtkTreeView:show-expanders:
704      *
705      * %TRUE if the view has expanders.
706      *
707      * Since: 2.12
708      */
709     g_object_class_install_property (o_class,
710                                      PROP_SHOW_EXPANDERS,
711                                      g_param_spec_boolean ("show-expanders",
712                                                            P_("Show Expanders"),
713                                                            P_("View has expanders"),
714                                                            TRUE,
715                                                            GTK_PARAM_READWRITE));
716
717     /**
718      * GtkTreeView:level-indentation:
719      *
720      * Extra indentation for each level.
721      *
722      * Since: 2.12
723      */
724     g_object_class_install_property (o_class,
725                                      PROP_LEVEL_INDENTATION,
726                                      g_param_spec_int ("level-indentation",
727                                                        P_("Level Indentation"),
728                                                        P_("Extra indentation for each level"),
729                                                        0,
730                                                        G_MAXINT,
731                                                        0,
732                                                        GTK_PARAM_READWRITE));
733
734     g_object_class_install_property (o_class,
735                                      PROP_RUBBER_BANDING,
736                                      g_param_spec_boolean ("rubber-banding",
737                                                            P_("Rubber Banding"),
738                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
739                                                            FALSE,
740                                                            GTK_PARAM_READWRITE));
741
742     g_object_class_install_property (o_class,
743                                      PROP_ENABLE_GRID_LINES,
744                                      g_param_spec_enum ("enable-grid-lines",
745                                                         P_("Enable Grid Lines"),
746                                                         P_("Whether grid lines should be drawn in the tree view"),
747                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
748                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
749                                                         GTK_PARAM_READWRITE));
750
751     g_object_class_install_property (o_class,
752                                      PROP_ENABLE_TREE_LINES,
753                                      g_param_spec_boolean ("enable-tree-lines",
754                                                            P_("Enable Tree Lines"),
755                                                            P_("Whether tree lines should be drawn in the tree view"),
756                                                            FALSE,
757                                                            GTK_PARAM_READWRITE));
758
759     g_object_class_install_property (o_class,
760                                      PROP_TOOLTIP_COLUMN,
761                                      g_param_spec_int ("tooltip-column",
762                                                        P_("Tooltip Column"),
763                                                        P_("The column in the model containing the tooltip texts for the rows"),
764                                                        -1,
765                                                        G_MAXINT,
766                                                        -1,
767                                                        GTK_PARAM_READWRITE));
768
769   /* Style properties */
770 #define _TREE_VIEW_EXPANDER_SIZE 12
771 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
772 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
773
774   gtk_widget_class_install_style_property (widget_class,
775                                            g_param_spec_int ("expander-size",
776                                                              P_("Expander Size"),
777                                                              P_("Size of the expander arrow"),
778                                                              0,
779                                                              G_MAXINT,
780                                                              _TREE_VIEW_EXPANDER_SIZE,
781                                                              GTK_PARAM_READABLE));
782
783   gtk_widget_class_install_style_property (widget_class,
784                                            g_param_spec_int ("vertical-separator",
785                                                              P_("Vertical Separator Width"),
786                                                              P_("Vertical space between cells.  Must be an even number"),
787                                                              0,
788                                                              G_MAXINT,
789                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
790                                                              GTK_PARAM_READABLE));
791
792   gtk_widget_class_install_style_property (widget_class,
793                                            g_param_spec_int ("horizontal-separator",
794                                                              P_("Horizontal Separator Width"),
795                                                              P_("Horizontal space between cells.  Must be an even number"),
796                                                              0,
797                                                              G_MAXINT,
798                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
799                                                              GTK_PARAM_READABLE));
800
801   gtk_widget_class_install_style_property (widget_class,
802                                            g_param_spec_boolean ("allow-rules",
803                                                                  P_("Allow Rules"),
804                                                                  P_("Allow drawing of alternating color rows"),
805                                                                  TRUE,
806                                                                  GTK_PARAM_READABLE));
807
808   gtk_widget_class_install_style_property (widget_class,
809                                            g_param_spec_boolean ("indent-expanders",
810                                                                  P_("Indent Expanders"),
811                                                                  P_("Make the expanders indented"),
812                                                                  TRUE,
813                                                                  GTK_PARAM_READABLE));
814
815   gtk_widget_class_install_style_property (widget_class,
816                                            g_param_spec_boxed ("even-row-color",
817                                                                P_("Even Row Color"),
818                                                                P_("Color to use for even rows"),
819                                                                GDK_TYPE_COLOR,
820                                                                GTK_PARAM_READABLE));
821
822   gtk_widget_class_install_style_property (widget_class,
823                                            g_param_spec_boxed ("odd-row-color",
824                                                                P_("Odd Row Color"),
825                                                                P_("Color to use for odd rows"),
826                                                                GDK_TYPE_COLOR,
827                                                                GTK_PARAM_READABLE));
828
829   gtk_widget_class_install_style_property (widget_class,
830                                            g_param_spec_int ("grid-line-width",
831                                                              P_("Grid line width"),
832                                                              P_("Width, in pixels, of the tree view grid lines"),
833                                                              0, G_MAXINT, 1,
834                                                              GTK_PARAM_READABLE));
835
836   gtk_widget_class_install_style_property (widget_class,
837                                            g_param_spec_int ("tree-line-width",
838                                                              P_("Tree line width"),
839                                                              P_("Width, in pixels, of the tree view lines"),
840                                                              0, G_MAXINT, 1,
841                                                              GTK_PARAM_READABLE));
842
843   gtk_widget_class_install_style_property (widget_class,
844                                            g_param_spec_string ("grid-line-pattern",
845                                                                 P_("Grid line pattern"),
846                                                                 P_("Dash pattern used to draw the tree view grid lines"),
847                                                                 "\1\1",
848                                                                 GTK_PARAM_READABLE));
849
850   gtk_widget_class_install_style_property (widget_class,
851                                            g_param_spec_string ("tree-line-pattern",
852                                                                 P_("Tree line pattern"),
853                                                                 P_("Dash pattern used to draw the tree view lines"),
854                                                                 "\1\1",
855                                                                 GTK_PARAM_READABLE));
856
857   /* Signals */
858   /**
859    * GtkTreeView::set-scroll-adjustments
860    * @horizontal: the horizontal #GtkAdjustment
861    * @vertical: the vertical #GtkAdjustment
862    *
863    * Set the scroll adjustments for the tree view. Usually scrolled containers
864    * like #GtkScrolledWindow will emit this signal to connect two instances
865    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
866    */
867   widget_class->set_scroll_adjustments_signal =
868     g_signal_new (I_("set-scroll-adjustments"),
869                   G_TYPE_FROM_CLASS (o_class),
870                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
871                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
872                   NULL, NULL,
873                   _gtk_marshal_VOID__OBJECT_OBJECT,
874                   G_TYPE_NONE, 2,
875                   GTK_TYPE_ADJUSTMENT,
876                   GTK_TYPE_ADJUSTMENT);
877
878   /**
879    * GtkTreeView::row-activated:
880    * @tree_view: the object on which the signal is emitted
881    * @path: the #GtkTreePath for the activated row
882    * @column: the #GtkTreeViewColumn in which the activation occurred
883    *
884    * The "row-activated" signal is emitted when the method
885    * gtk_tree_view_row_activated() is called or the user double clicks 
886    * a treeview row. It is also emitted when a non-editable row is 
887    * selected and one of the keys: Space, Shift+Space, Return or 
888    * Enter is pressed.
889    * 
890    * For selection handling refer to the <link linkend="TreeWidget">tree 
891    * widget conceptual overview</link> as well as #GtkTreeSelection.
892    */
893   tree_view_signals[ROW_ACTIVATED] =
894     g_signal_new (I_("row-activated"),
895                   G_TYPE_FROM_CLASS (o_class),
896                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
897                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
898                   NULL, NULL,
899                   _gtk_marshal_VOID__BOXED_OBJECT,
900                   G_TYPE_NONE, 2,
901                   GTK_TYPE_TREE_PATH,
902                   GTK_TYPE_TREE_VIEW_COLUMN);
903
904   /**
905    * GtkTreeView::test-expand-row:
906    * @tree_view: the object on which the signal is emitted
907    * @iter: the tree iter of the row to expand
908    * @path: a tree path that points to the row 
909    * 
910    * The given row is about to be expanded (show its children nodes). Use this
911    * signal if you need to control the expandability of individual rows.
912    *
913    * Returns: %FALSE to allow expansion, %TRUE to reject
914    */
915   tree_view_signals[TEST_EXPAND_ROW] =
916     g_signal_new (I_("test-expand-row"),
917                   G_TYPE_FROM_CLASS (o_class),
918                   G_SIGNAL_RUN_LAST,
919                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
920                   _gtk_boolean_handled_accumulator, NULL,
921                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
922                   G_TYPE_BOOLEAN, 2,
923                   GTK_TYPE_TREE_ITER,
924                   GTK_TYPE_TREE_PATH);
925
926   /**
927    * GtkTreeView::test-collapse-row:
928    * @tree_view: the object on which the signal is emitted
929    * @iter: the tree iter of the row to collapse
930    * @path: a tree path that points to the row 
931    * 
932    * The given row is about to be collapsed (hide its children nodes). Use this
933    * signal if you need to control the collapsibility of individual rows.
934    *
935    * Returns: %FALSE to allow collapsing, %TRUE to reject
936    */
937   tree_view_signals[TEST_COLLAPSE_ROW] =
938     g_signal_new (I_("test-collapse-row"),
939                   G_TYPE_FROM_CLASS (o_class),
940                   G_SIGNAL_RUN_LAST,
941                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
942                   _gtk_boolean_handled_accumulator, NULL,
943                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
944                   G_TYPE_BOOLEAN, 2,
945                   GTK_TYPE_TREE_ITER,
946                   GTK_TYPE_TREE_PATH);
947
948   /**
949    * GtkTreeView::row-expanded:
950    * @tree_view: the object on which the signal is emitted
951    * @iter: the tree iter of the expanded row
952    * @path: a tree path that points to the row 
953    * 
954    * The given row has been expanded (child nodes are shown).
955    */
956   tree_view_signals[ROW_EXPANDED] =
957     g_signal_new (I_("row-expanded"),
958                   G_TYPE_FROM_CLASS (o_class),
959                   G_SIGNAL_RUN_LAST,
960                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
961                   NULL, NULL,
962                   _gtk_marshal_VOID__BOXED_BOXED,
963                   G_TYPE_NONE, 2,
964                   GTK_TYPE_TREE_ITER,
965                   GTK_TYPE_TREE_PATH);
966
967   /**
968    * GtkTreeView::row-collapsed:
969    * @tree_view: the object on which the signal is emitted
970    * @iter: the tree iter of the collapsed row
971    * @path: a tree path that points to the row 
972    * 
973    * The given row has been collapsed (child nodes are hidden).
974    */
975   tree_view_signals[ROW_COLLAPSED] =
976     g_signal_new (I_("row-collapsed"),
977                   G_TYPE_FROM_CLASS (o_class),
978                   G_SIGNAL_RUN_LAST,
979                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
980                   NULL, NULL,
981                   _gtk_marshal_VOID__BOXED_BOXED,
982                   G_TYPE_NONE, 2,
983                   GTK_TYPE_TREE_ITER,
984                   GTK_TYPE_TREE_PATH);
985
986   /**
987    * GtkTreeView::columns-changed:
988    * @tree_view: the object on which the signal is emitted 
989    * 
990    * The number of columns of the treeview has changed.
991    */
992   tree_view_signals[COLUMNS_CHANGED] =
993     g_signal_new (I_("columns-changed"),
994                   G_TYPE_FROM_CLASS (o_class),
995                   G_SIGNAL_RUN_LAST,
996                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
997                   NULL, NULL,
998                   _gtk_marshal_VOID__VOID,
999                   G_TYPE_NONE, 0);
1000
1001   /**
1002    * GtkTreeView::cursor-changed:
1003    * @tree_view: the object on which the signal is emitted
1004    * 
1005    * The position of the cursor (focused cell) has changed.
1006    */
1007   tree_view_signals[CURSOR_CHANGED] =
1008     g_signal_new (I_("cursor-changed"),
1009                   G_TYPE_FROM_CLASS (o_class),
1010                   G_SIGNAL_RUN_LAST,
1011                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1012                   NULL, NULL,
1013                   _gtk_marshal_VOID__VOID,
1014                   G_TYPE_NONE, 0);
1015
1016   tree_view_signals[MOVE_CURSOR] =
1017     g_signal_new (I_("move-cursor"),
1018                   G_TYPE_FROM_CLASS (o_class),
1019                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1020                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1021                   NULL, NULL,
1022                   _gtk_marshal_BOOLEAN__ENUM_INT,
1023                   G_TYPE_BOOLEAN, 2,
1024                   GTK_TYPE_MOVEMENT_STEP,
1025                   G_TYPE_INT);
1026
1027   tree_view_signals[SELECT_ALL] =
1028     g_signal_new (I_("select-all"),
1029                   G_TYPE_FROM_CLASS (o_class),
1030                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1031                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1032                   NULL, NULL,
1033                   _gtk_marshal_BOOLEAN__VOID,
1034                   G_TYPE_BOOLEAN, 0);
1035
1036   tree_view_signals[UNSELECT_ALL] =
1037     g_signal_new (I_("unselect-all"),
1038                   G_TYPE_FROM_CLASS (o_class),
1039                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1040                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1041                   NULL, NULL,
1042                   _gtk_marshal_BOOLEAN__VOID,
1043                   G_TYPE_BOOLEAN, 0);
1044
1045   tree_view_signals[SELECT_CURSOR_ROW] =
1046     g_signal_new (I_("select-cursor-row"),
1047                   G_TYPE_FROM_CLASS (o_class),
1048                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1049                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1050                   NULL, NULL,
1051                   _gtk_marshal_BOOLEAN__BOOLEAN,
1052                   G_TYPE_BOOLEAN, 1,
1053                   G_TYPE_BOOLEAN);
1054
1055   tree_view_signals[TOGGLE_CURSOR_ROW] =
1056     g_signal_new (I_("toggle-cursor-row"),
1057                   G_TYPE_FROM_CLASS (o_class),
1058                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1059                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1060                   NULL, NULL,
1061                   _gtk_marshal_BOOLEAN__VOID,
1062                   G_TYPE_BOOLEAN, 0);
1063
1064   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1065     g_signal_new (I_("expand-collapse-cursor-row"),
1066                   G_TYPE_FROM_CLASS (o_class),
1067                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1068                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1069                   NULL, NULL,
1070                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1071                   G_TYPE_BOOLEAN, 3,
1072                   G_TYPE_BOOLEAN,
1073                   G_TYPE_BOOLEAN,
1074                   G_TYPE_BOOLEAN);
1075
1076   tree_view_signals[SELECT_CURSOR_PARENT] =
1077     g_signal_new (I_("select-cursor-parent"),
1078                   G_TYPE_FROM_CLASS (o_class),
1079                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1080                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1081                   NULL, NULL,
1082                   _gtk_marshal_BOOLEAN__VOID,
1083                   G_TYPE_BOOLEAN, 0);
1084
1085   tree_view_signals[START_INTERACTIVE_SEARCH] =
1086     g_signal_new (I_("start-interactive-search"),
1087                   G_TYPE_FROM_CLASS (o_class),
1088                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1089                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1090                   NULL, NULL,
1091                   _gtk_marshal_BOOLEAN__VOID,
1092                   G_TYPE_BOOLEAN, 0);
1093
1094   /* Key bindings */
1095   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1096                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1097   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1098                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1099
1100   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1101                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1102   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1103                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1104
1105   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1106                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1107
1108   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1109                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1110
1111   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1112                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1113   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1114                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1115
1116   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1117                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1118   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1119                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1120
1121   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1122                                   GTK_MOVEMENT_PAGES, -1);
1123   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1124                                   GTK_MOVEMENT_PAGES, -1);
1125
1126   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1127                                   GTK_MOVEMENT_PAGES, 1);
1128   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1129                                   GTK_MOVEMENT_PAGES, 1);
1130
1131
1132   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1133                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1134                                 G_TYPE_INT, 1);
1135
1136   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1137                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1138                                 G_TYPE_INT, -1);
1139
1140   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1141                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1142                                 G_TYPE_INT, 1);
1143
1144   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1145                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1146                                 G_TYPE_INT, -1);
1147
1148   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1149                                 "move-cursor", 2,
1150                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1151                                 G_TYPE_INT, 1);
1152
1153   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1154                                 "move-cursor", 2,
1155                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1156                                 G_TYPE_INT, -1);
1157
1158   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1159                                 "move-cursor", 2,
1160                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1161                                 G_TYPE_INT, 1);
1162
1163   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1164                                 "move-cursor", 2,
1165                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1166                                 G_TYPE_INT, -1);
1167
1168   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1169   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1170
1171   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1172   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1173
1174   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1175   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1176
1177   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1178                                 G_TYPE_BOOLEAN, TRUE);
1179   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1180                                 G_TYPE_BOOLEAN, TRUE);
1181
1182   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1183                                 G_TYPE_BOOLEAN, TRUE);
1184   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1185                                 G_TYPE_BOOLEAN, TRUE);
1186   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1187                                 G_TYPE_BOOLEAN, TRUE);
1188   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1189                                 G_TYPE_BOOLEAN, TRUE);
1190   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1191                                 G_TYPE_BOOLEAN, TRUE);
1192
1193   /* expand and collapse rows */
1194   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1195                                 G_TYPE_BOOLEAN, TRUE,
1196                                 G_TYPE_BOOLEAN, TRUE,
1197                                 G_TYPE_BOOLEAN, FALSE);
1198
1199   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1200                                 "expand-collapse-cursor-row", 3,
1201                                 G_TYPE_BOOLEAN, TRUE,
1202                                 G_TYPE_BOOLEAN, TRUE,
1203                                 G_TYPE_BOOLEAN, TRUE);
1204   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1205                                 "expand-collapse-cursor-row", 3,
1206                                 G_TYPE_BOOLEAN, TRUE,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE);
1209
1210   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1211                                 "expand-collapse-cursor-row", 3,
1212                                 G_TYPE_BOOLEAN, TRUE,
1213                                 G_TYPE_BOOLEAN, FALSE,
1214                                 G_TYPE_BOOLEAN, FALSE);
1215   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1216                                 "expand-collapse-cursor-row", 3,
1217                                 G_TYPE_BOOLEAN, TRUE,
1218                                 G_TYPE_BOOLEAN, FALSE,
1219                                 G_TYPE_BOOLEAN, FALSE);
1220
1221   /* Not doable on US keyboards */
1222   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1223                                 G_TYPE_BOOLEAN, TRUE,
1224                                 G_TYPE_BOOLEAN, TRUE,
1225                                 G_TYPE_BOOLEAN, TRUE);
1226   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1227                                 G_TYPE_BOOLEAN, TRUE,
1228                                 G_TYPE_BOOLEAN, TRUE,
1229                                 G_TYPE_BOOLEAN, FALSE);
1230   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1231                                 G_TYPE_BOOLEAN, TRUE,
1232                                 G_TYPE_BOOLEAN, TRUE,
1233                                 G_TYPE_BOOLEAN, TRUE);
1234   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1235                                 G_TYPE_BOOLEAN, TRUE,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, TRUE);
1238   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1239                                 "expand-collapse-cursor-row", 3,
1240                                 G_TYPE_BOOLEAN, FALSE,
1241                                 G_TYPE_BOOLEAN, TRUE,
1242                                 G_TYPE_BOOLEAN, TRUE);
1243   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1244                                 "expand-collapse-cursor-row", 3,
1245                                 G_TYPE_BOOLEAN, FALSE,
1246                                 G_TYPE_BOOLEAN, TRUE,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1249                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1250                                 "expand-collapse-cursor-row", 3,
1251                                 G_TYPE_BOOLEAN, FALSE,
1252                                 G_TYPE_BOOLEAN, TRUE,
1253                                 G_TYPE_BOOLEAN, TRUE);
1254   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1255                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1256                                 "expand-collapse-cursor-row", 3,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, TRUE,
1259                                 G_TYPE_BOOLEAN, TRUE);
1260
1261   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1262                                 G_TYPE_BOOLEAN, TRUE,
1263                                 G_TYPE_BOOLEAN, FALSE,
1264                                 G_TYPE_BOOLEAN, FALSE);
1265   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1266                                 G_TYPE_BOOLEAN, TRUE,
1267                                 G_TYPE_BOOLEAN, FALSE,
1268                                 G_TYPE_BOOLEAN, TRUE);
1269   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1270                                 G_TYPE_BOOLEAN, TRUE,
1271                                 G_TYPE_BOOLEAN, FALSE,
1272                                 G_TYPE_BOOLEAN, FALSE);
1273   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1274                                 G_TYPE_BOOLEAN, TRUE,
1275                                 G_TYPE_BOOLEAN, FALSE,
1276                                 G_TYPE_BOOLEAN, TRUE);
1277   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1278                                 "expand-collapse-cursor-row", 3,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, FALSE,
1281                                 G_TYPE_BOOLEAN, TRUE);
1282   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1283                                 "expand-collapse-cursor-row", 3,
1284                                 G_TYPE_BOOLEAN, FALSE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, TRUE);
1287   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1288                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1289                                 "expand-collapse-cursor-row", 3,
1290                                 G_TYPE_BOOLEAN, FALSE,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, TRUE);
1293   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1294                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1295                                 "expand-collapse-cursor-row", 3,
1296                                 G_TYPE_BOOLEAN, FALSE,
1297                                 G_TYPE_BOOLEAN, FALSE,
1298                                 G_TYPE_BOOLEAN, TRUE);
1299
1300   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1301   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1302
1303   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1304
1305   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1306
1307   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1308 }
1309
1310 static void
1311 gtk_tree_view_init (GtkTreeView *tree_view)
1312 {
1313   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1314
1315   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1316   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1317
1318   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1319                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1320                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1321
1322   /* We need some padding */
1323   tree_view->priv->dy = 0;
1324   tree_view->priv->cursor_offset = 0;
1325   tree_view->priv->n_columns = 0;
1326   tree_view->priv->header_height = 1;
1327   tree_view->priv->x_drag = 0;
1328   tree_view->priv->drag_pos = -1;
1329   tree_view->priv->header_has_focus = FALSE;
1330   tree_view->priv->pressed_button = -1;
1331   tree_view->priv->press_start_x = -1;
1332   tree_view->priv->press_start_y = -1;
1333   tree_view->priv->reorderable = FALSE;
1334   tree_view->priv->presize_handler_timer = 0;
1335   tree_view->priv->scroll_sync_timer = 0;
1336   tree_view->priv->fixed_height = -1;
1337   tree_view->priv->fixed_height_mode = FALSE;
1338   tree_view->priv->fixed_height_check = 0;
1339   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1340   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1341   tree_view->priv->enable_search = TRUE;
1342   tree_view->priv->search_column = -1;
1343   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1344   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1345   tree_view->priv->search_custom_entry_set = FALSE;
1346   tree_view->priv->typeselect_flush_timeout = 0;
1347   tree_view->priv->init_hadjust_value = TRUE;    
1348   tree_view->priv->width = 0;
1349           
1350   tree_view->priv->hover_selection = FALSE;
1351   tree_view->priv->hover_expand = FALSE;
1352
1353   tree_view->priv->level_indentation = 0;
1354
1355   tree_view->priv->rubber_banding_enable = FALSE;
1356
1357   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1358   tree_view->priv->tree_lines_enabled = FALSE;
1359
1360   tree_view->priv->tooltip_column = -1;
1361
1362   tree_view->priv->post_validation_flag = FALSE;
1363
1364   tree_view->priv->last_button_x = -1;
1365   tree_view->priv->last_button_y = -1;
1366
1367   tree_view->priv->event_last_x = -10000;
1368   tree_view->priv->event_last_y = -10000;
1369 }
1370
1371 \f
1372
1373 /* GObject Methods
1374  */
1375
1376 static void
1377 gtk_tree_view_set_property (GObject         *object,
1378                             guint            prop_id,
1379                             const GValue    *value,
1380                             GParamSpec      *pspec)
1381 {
1382   GtkTreeView *tree_view;
1383
1384   tree_view = GTK_TREE_VIEW (object);
1385
1386   switch (prop_id)
1387     {
1388     case PROP_MODEL:
1389       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1390       break;
1391     case PROP_HADJUSTMENT:
1392       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1393       break;
1394     case PROP_VADJUSTMENT:
1395       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1396       break;
1397     case PROP_HEADERS_VISIBLE:
1398       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1399       break;
1400     case PROP_HEADERS_CLICKABLE:
1401       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1402       break;
1403     case PROP_EXPANDER_COLUMN:
1404       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1405       break;
1406     case PROP_REORDERABLE:
1407       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1408       break;
1409     case PROP_RULES_HINT:
1410       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1411       break;
1412     case PROP_ENABLE_SEARCH:
1413       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1414       break;
1415     case PROP_SEARCH_COLUMN:
1416       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1417       break;
1418     case PROP_FIXED_HEIGHT_MODE:
1419       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1420       break;
1421     case PROP_HOVER_SELECTION:
1422       tree_view->priv->hover_selection = g_value_get_boolean (value);
1423       break;
1424     case PROP_HOVER_EXPAND:
1425       tree_view->priv->hover_expand = g_value_get_boolean (value);
1426       break;
1427     case PROP_SHOW_EXPANDERS:
1428       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1429       break;
1430     case PROP_LEVEL_INDENTATION:
1431       tree_view->priv->level_indentation = g_value_get_int (value);
1432       break;
1433     case PROP_RUBBER_BANDING:
1434       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1435       break;
1436     case PROP_ENABLE_GRID_LINES:
1437       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1438       break;
1439     case PROP_ENABLE_TREE_LINES:
1440       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1441       break;
1442     case PROP_TOOLTIP_COLUMN:
1443       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1444       break;
1445     default:
1446       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1447       break;
1448     }
1449 }
1450
1451 static void
1452 gtk_tree_view_get_property (GObject    *object,
1453                             guint       prop_id,
1454                             GValue     *value,
1455                             GParamSpec *pspec)
1456 {
1457   GtkTreeView *tree_view;
1458
1459   tree_view = GTK_TREE_VIEW (object);
1460
1461   switch (prop_id)
1462     {
1463     case PROP_MODEL:
1464       g_value_set_object (value, tree_view->priv->model);
1465       break;
1466     case PROP_HADJUSTMENT:
1467       g_value_set_object (value, tree_view->priv->hadjustment);
1468       break;
1469     case PROP_VADJUSTMENT:
1470       g_value_set_object (value, tree_view->priv->vadjustment);
1471       break;
1472     case PROP_HEADERS_VISIBLE:
1473       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1474       break;
1475     case PROP_HEADERS_CLICKABLE:
1476       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1477       break;
1478     case PROP_EXPANDER_COLUMN:
1479       g_value_set_object (value, tree_view->priv->expander_column);
1480       break;
1481     case PROP_REORDERABLE:
1482       g_value_set_boolean (value, tree_view->priv->reorderable);
1483       break;
1484     case PROP_RULES_HINT:
1485       g_value_set_boolean (value, tree_view->priv->has_rules);
1486       break;
1487     case PROP_ENABLE_SEARCH:
1488       g_value_set_boolean (value, tree_view->priv->enable_search);
1489       break;
1490     case PROP_SEARCH_COLUMN:
1491       g_value_set_int (value, tree_view->priv->search_column);
1492       break;
1493     case PROP_FIXED_HEIGHT_MODE:
1494       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1495       break;
1496     case PROP_HOVER_SELECTION:
1497       g_value_set_boolean (value, tree_view->priv->hover_selection);
1498       break;
1499     case PROP_HOVER_EXPAND:
1500       g_value_set_boolean (value, tree_view->priv->hover_expand);
1501       break;
1502     case PROP_SHOW_EXPANDERS:
1503       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1504       break;
1505     case PROP_LEVEL_INDENTATION:
1506       g_value_set_int (value, tree_view->priv->level_indentation);
1507       break;
1508     case PROP_RUBBER_BANDING:
1509       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1510       break;
1511     case PROP_ENABLE_GRID_LINES:
1512       g_value_set_enum (value, tree_view->priv->grid_lines);
1513       break;
1514     case PROP_ENABLE_TREE_LINES:
1515       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1516       break;
1517     case PROP_TOOLTIP_COLUMN:
1518       g_value_set_int (value, tree_view->priv->tooltip_column);
1519       break;
1520     default:
1521       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1522       break;
1523     }
1524 }
1525
1526 static void
1527 gtk_tree_view_finalize (GObject *object)
1528 {
1529   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1530 }
1531
1532
1533 static GtkBuildableIface *parent_buildable_iface;
1534
1535 static void
1536 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1537 {
1538   parent_buildable_iface = g_type_interface_peek_parent (iface);
1539   iface->add_child = gtk_tree_view_buildable_add_child;
1540   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1541 }
1542
1543 static void
1544 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1545                                    GtkBuilder  *builder,
1546                                    GObject     *child,
1547                                    const gchar *type)
1548 {
1549   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1550 }
1551
1552 static GObject *
1553 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1554                                             GtkBuilder        *builder,
1555                                             const gchar       *childname)
1556 {
1557     if (strcmp (childname, "selection") == 0)
1558       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1559     
1560     return parent_buildable_iface->get_internal_child (buildable,
1561                                                        builder,
1562                                                        childname);
1563 }
1564
1565 /* GtkWidget Methods
1566  */
1567
1568 static void
1569 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1570 {
1571   _gtk_rbtree_free (tree_view->priv->tree);
1572   
1573   tree_view->priv->tree = NULL;
1574   tree_view->priv->button_pressed_node = NULL;
1575   tree_view->priv->button_pressed_tree = NULL;
1576   tree_view->priv->prelight_tree = NULL;
1577   tree_view->priv->prelight_node = NULL;
1578   tree_view->priv->expanded_collapsed_node = NULL;
1579   tree_view->priv->expanded_collapsed_tree = NULL;
1580 }
1581
1582 static void
1583 gtk_tree_view_destroy (GtkWidget *widget)
1584 {
1585   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1586   GList *list;
1587
1588   gtk_tree_view_stop_editing (tree_view, TRUE);
1589
1590   if (tree_view->priv->columns != NULL)
1591     {
1592       list = tree_view->priv->columns;
1593       while (list)
1594         {
1595           GtkTreeViewColumn *column;
1596           column = GTK_TREE_VIEW_COLUMN (list->data);
1597           list = list->next;
1598           gtk_tree_view_remove_column (tree_view, column);
1599         }
1600       tree_view->priv->columns = NULL;
1601     }
1602
1603   if (tree_view->priv->tree != NULL)
1604     {
1605       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1606
1607       gtk_tree_view_free_rbtree (tree_view);
1608     }
1609
1610   if (tree_view->priv->selection != NULL)
1611     {
1612       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1613       g_object_unref (tree_view->priv->selection);
1614       tree_view->priv->selection = NULL;
1615     }
1616
1617   if (tree_view->priv->scroll_to_path != NULL)
1618     {
1619       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1620       tree_view->priv->scroll_to_path = NULL;
1621     }
1622
1623   if (tree_view->priv->drag_dest_row != NULL)
1624     {
1625       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1626       tree_view->priv->drag_dest_row = NULL;
1627     }
1628
1629   if (tree_view->priv->top_row != NULL)
1630     {
1631       gtk_tree_row_reference_free (tree_view->priv->top_row);
1632       tree_view->priv->top_row = NULL;
1633     }
1634
1635   if (tree_view->priv->column_drop_func_data &&
1636       tree_view->priv->column_drop_func_data_destroy)
1637     {
1638       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1639       tree_view->priv->column_drop_func_data = NULL;
1640     }
1641
1642   if (tree_view->priv->destroy_count_destroy &&
1643       tree_view->priv->destroy_count_data)
1644     {
1645       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1646       tree_view->priv->destroy_count_data = NULL;
1647     }
1648
1649   gtk_tree_row_reference_free (tree_view->priv->cursor);
1650   tree_view->priv->cursor = NULL;
1651
1652   gtk_tree_row_reference_free (tree_view->priv->anchor);
1653   tree_view->priv->anchor = NULL;
1654
1655   /* destroy interactive search dialog */
1656   if (tree_view->priv->search_window)
1657     {
1658       gtk_widget_destroy (tree_view->priv->search_window);
1659       tree_view->priv->search_window = NULL;
1660       tree_view->priv->search_entry = NULL;
1661       if (tree_view->priv->typeselect_flush_timeout)
1662         {
1663           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1664           tree_view->priv->typeselect_flush_timeout = 0;
1665         }
1666     }
1667
1668   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1669     {
1670       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1671       tree_view->priv->search_user_data = NULL;
1672     }
1673
1674   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1675     {
1676       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1677       tree_view->priv->search_position_user_data = NULL;
1678     }
1679
1680   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1681     {
1682       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1683       tree_view->priv->row_separator_data = NULL;
1684     }
1685   
1686   gtk_tree_view_set_model (tree_view, NULL);
1687
1688   if (tree_view->priv->hadjustment)
1689     {
1690       g_object_unref (tree_view->priv->hadjustment);
1691       tree_view->priv->hadjustment = NULL;
1692     }
1693   if (tree_view->priv->vadjustment)
1694     {
1695       g_object_unref (tree_view->priv->vadjustment);
1696       tree_view->priv->vadjustment = NULL;
1697     }
1698
1699   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
1700 }
1701
1702 /* GtkWidget::map helper */
1703 static void
1704 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1705 {
1706   GList *list;
1707
1708   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1709
1710   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1711     {
1712       GtkTreeViewColumn *column;
1713
1714       for (list = tree_view->priv->columns; list; list = list->next)
1715         {
1716           column = list->data;
1717           if (gtk_widget_get_visible (column->button) &&
1718               !gtk_widget_get_mapped (column->button))
1719             gtk_widget_map (column->button);
1720         }
1721       for (list = tree_view->priv->columns; list; list = list->next)
1722         {
1723           column = list->data;
1724           if (column->visible == FALSE)
1725             continue;
1726           if (column->resizable)
1727             {
1728               gdk_window_raise (column->window);
1729               gdk_window_show (column->window);
1730             }
1731           else
1732             gdk_window_hide (column->window);
1733         }
1734       gdk_window_show (tree_view->priv->header_window);
1735     }
1736 }
1737
1738 static void
1739 gtk_tree_view_map (GtkWidget *widget)
1740 {
1741   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1742   GList *tmp_list;
1743
1744   gtk_widget_set_mapped (widget, TRUE);
1745
1746   tmp_list = tree_view->priv->children;
1747   while (tmp_list)
1748     {
1749       GtkTreeViewChild *child = tmp_list->data;
1750       tmp_list = tmp_list->next;
1751
1752       if (gtk_widget_get_visible (child->widget))
1753         {
1754           if (!gtk_widget_get_mapped (child->widget))
1755             gtk_widget_map (child->widget);
1756         }
1757     }
1758   gdk_window_show (tree_view->priv->bin_window);
1759
1760   gtk_tree_view_map_buttons (tree_view);
1761
1762   gdk_window_show (gtk_widget_get_window (widget));
1763 }
1764
1765 static void
1766 gtk_tree_view_realize (GtkWidget *widget)
1767 {
1768   GtkAllocation allocation;
1769   GtkStyle *style;
1770   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1771   GdkWindow *window;
1772   GdkWindowAttr attributes;
1773   GList *tmp_list;
1774   gint attributes_mask;
1775
1776   gtk_widget_set_realized (widget, TRUE);
1777
1778   gtk_widget_get_allocation (widget, &allocation);
1779
1780   /* Make the main, clipping window */
1781   attributes.window_type = GDK_WINDOW_CHILD;
1782   attributes.x = allocation.x;
1783   attributes.y = allocation.y;
1784   attributes.width = allocation.width;
1785   attributes.height = allocation.height;
1786   attributes.wclass = GDK_INPUT_OUTPUT;
1787   attributes.visual = gtk_widget_get_visual (widget);
1788   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1789
1790   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1791
1792   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1793                            &attributes, attributes_mask);
1794   gtk_widget_set_window (widget, window);
1795   gdk_window_set_user_data (window, widget);
1796
1797   gtk_widget_get_allocation (widget, &allocation);
1798
1799   /* Make the window for the tree */
1800   attributes.x = 0;
1801   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1802   attributes.width = MAX (tree_view->priv->width, allocation.width);
1803   attributes.height = allocation.height;
1804   attributes.event_mask = (GDK_EXPOSURE_MASK |
1805                            GDK_SCROLL_MASK |
1806                            GDK_POINTER_MOTION_MASK |
1807                            GDK_ENTER_NOTIFY_MASK |
1808                            GDK_LEAVE_NOTIFY_MASK |
1809                            GDK_BUTTON_PRESS_MASK |
1810                            GDK_BUTTON_RELEASE_MASK |
1811                            gtk_widget_get_events (widget));
1812
1813   tree_view->priv->bin_window = gdk_window_new (window,
1814                                                 &attributes, attributes_mask);
1815   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1816
1817   gtk_widget_get_allocation (widget, &allocation);
1818
1819   /* Make the column header window */
1820   attributes.x = 0;
1821   attributes.y = 0;
1822   attributes.width = MAX (tree_view->priv->width, allocation.width);
1823   attributes.height = tree_view->priv->header_height;
1824   attributes.event_mask = (GDK_EXPOSURE_MASK |
1825                            GDK_SCROLL_MASK |
1826                            GDK_ENTER_NOTIFY_MASK |
1827                            GDK_LEAVE_NOTIFY_MASK |
1828                            GDK_BUTTON_PRESS_MASK |
1829                            GDK_BUTTON_RELEASE_MASK |
1830                            GDK_KEY_PRESS_MASK |
1831                            GDK_KEY_RELEASE_MASK |
1832                            gtk_widget_get_events (widget));
1833
1834   tree_view->priv->header_window = gdk_window_new (window,
1835                                                    &attributes, attributes_mask);
1836   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1837
1838   /* Add them all up. */
1839   gtk_widget_style_attach (widget);
1840   style = gtk_widget_get_style (widget);
1841   gdk_window_set_background (tree_view->priv->bin_window,
1842                              &style->base[gtk_widget_get_state (widget)]);
1843   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1844
1845   tmp_list = tree_view->priv->children;
1846   while (tmp_list)
1847     {
1848       GtkTreeViewChild *child = tmp_list->data;
1849       tmp_list = tmp_list->next;
1850
1851       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1852     }
1853
1854   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1855     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1856
1857   /* Need to call those here, since they create GCs */
1858   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1859   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1860
1861   install_presize_handler (tree_view); 
1862 }
1863
1864 static void
1865 gtk_tree_view_unrealize (GtkWidget *widget)
1866 {
1867   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1868   GtkTreeViewPrivate *priv = tree_view->priv;
1869   GList *list;
1870
1871   if (priv->scroll_timeout != 0)
1872     {
1873       g_source_remove (priv->scroll_timeout);
1874       priv->scroll_timeout = 0;
1875     }
1876
1877   if (priv->auto_expand_timeout != 0)
1878     {
1879       g_source_remove (priv->auto_expand_timeout);
1880       priv->auto_expand_timeout = 0;
1881     }
1882
1883   if (priv->open_dest_timeout != 0)
1884     {
1885       g_source_remove (priv->open_dest_timeout);
1886       priv->open_dest_timeout = 0;
1887     }
1888
1889   remove_expand_collapse_timeout (tree_view);
1890   
1891   if (priv->presize_handler_timer != 0)
1892     {
1893       g_source_remove (priv->presize_handler_timer);
1894       priv->presize_handler_timer = 0;
1895     }
1896
1897   if (priv->validate_rows_timer != 0)
1898     {
1899       g_source_remove (priv->validate_rows_timer);
1900       priv->validate_rows_timer = 0;
1901     }
1902
1903   if (priv->scroll_sync_timer != 0)
1904     {
1905       g_source_remove (priv->scroll_sync_timer);
1906       priv->scroll_sync_timer = 0;
1907     }
1908
1909   if (priv->typeselect_flush_timeout)
1910     {
1911       g_source_remove (priv->typeselect_flush_timeout);
1912       priv->typeselect_flush_timeout = 0;
1913     }
1914   
1915   for (list = priv->columns; list; list = list->next)
1916     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1917
1918   gdk_window_set_user_data (priv->bin_window, NULL);
1919   gdk_window_destroy (priv->bin_window);
1920   priv->bin_window = NULL;
1921
1922   gdk_window_set_user_data (priv->header_window, NULL);
1923   gdk_window_destroy (priv->header_window);
1924   priv->header_window = NULL;
1925
1926   if (priv->drag_window)
1927     {
1928       gdk_window_set_user_data (priv->drag_window, NULL);
1929       gdk_window_destroy (priv->drag_window);
1930       priv->drag_window = NULL;
1931     }
1932
1933   if (priv->drag_highlight_window)
1934     {
1935       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1936       gdk_window_destroy (priv->drag_highlight_window);
1937       priv->drag_highlight_window = NULL;
1938     }
1939
1940   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1941 }
1942
1943 /* GtkWidget::size_request helper */
1944 static void
1945 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1946 {
1947   GList *list;
1948
1949   tree_view->priv->header_height = 0;
1950
1951   if (tree_view->priv->model)
1952     {
1953       for (list = tree_view->priv->columns; list; list = list->next)
1954         {
1955           GtkRequisition requisition;
1956           GtkTreeViewColumn *column = list->data;
1957
1958           if (column->button == NULL)
1959             continue;
1960
1961           column = list->data;
1962
1963           gtk_widget_get_preferred_size (column->button, &requisition, NULL);
1964           column->button_request = requisition.width;
1965           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1966         }
1967     }
1968 }
1969
1970
1971 /* Called only by ::size_request */
1972 static void
1973 gtk_tree_view_update_size (GtkTreeView *tree_view)
1974 {
1975   GList *list;
1976   GtkTreeViewColumn *column;
1977   gint i;
1978
1979   if (tree_view->priv->model == NULL)
1980     {
1981       tree_view->priv->width = 0;
1982       tree_view->priv->prev_width = 0;                   
1983       tree_view->priv->height = 0;
1984       return;
1985     }
1986
1987   tree_view->priv->prev_width = tree_view->priv->width;  
1988   tree_view->priv->width = 0;
1989
1990   /* keep this in sync with size_allocate below */
1991   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1992     {
1993       gint real_requested_width = 0;
1994       column = list->data;
1995       if (!column->visible)
1996         continue;
1997
1998       if (column->use_resized_width)
1999         {
2000           real_requested_width = column->resized_width;
2001         }
2002       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2003         {
2004           real_requested_width = column->fixed_width;
2005         }
2006       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2007         {
2008           real_requested_width = MAX (column->requested_width, column->button_request);
2009         }
2010       else
2011         {
2012           real_requested_width = column->requested_width;
2013         }
2014
2015       if (column->min_width != -1)
2016         real_requested_width = MAX (real_requested_width, column->min_width);
2017       if (column->max_width != -1)
2018         real_requested_width = MIN (real_requested_width, column->max_width);
2019
2020       tree_view->priv->width += real_requested_width;
2021     }
2022
2023   if (tree_view->priv->tree == NULL)
2024     tree_view->priv->height = 0;
2025   else
2026     tree_view->priv->height = tree_view->priv->tree->root->offset;
2027 }
2028
2029 static void
2030 gtk_tree_view_size_request (GtkWidget      *widget,
2031                             GtkRequisition *requisition)
2032 {
2033   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2034   GList *tmp_list;
2035
2036   /* we validate some rows initially just to make sure we have some size. 
2037    * In practice, with a lot of static lists, this should get a good width.
2038    */
2039   do_validate_rows (tree_view, FALSE);
2040   gtk_tree_view_size_request_columns (tree_view);
2041   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2042
2043   requisition->width = tree_view->priv->width;
2044   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2045
2046   tmp_list = tree_view->priv->children;
2047
2048   while (tmp_list)
2049     {
2050       GtkTreeViewChild *child = tmp_list->data;
2051       GtkRequisition child_requisition;
2052
2053       tmp_list = tmp_list->next;
2054
2055       if (gtk_widget_get_visible (child->widget))
2056         gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
2057     }
2058 }
2059
2060 static int
2061 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2062 {
2063   int width = 0;
2064   GList *list;
2065   gboolean rtl;
2066
2067   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2068   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2069        list->data != tree_view->priv->expander_column;
2070        list = (rtl ? list->prev : list->next))
2071     {
2072       GtkTreeViewColumn *column = list->data;
2073
2074       width += column->width;
2075     }
2076
2077   return width;
2078 }
2079
2080 static void
2081 invalidate_column (GtkTreeView       *tree_view,
2082                    GtkTreeViewColumn *column)
2083 {
2084   gint column_offset = 0;
2085   GList *list;
2086   GtkWidget *widget = GTK_WIDGET (tree_view);
2087   gboolean rtl;
2088
2089   if (!gtk_widget_get_realized (widget))
2090     return;
2091
2092   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2093   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2094        list;
2095        list = (rtl ? list->prev : list->next))
2096     {
2097       GtkTreeViewColumn *tmpcolumn = list->data;
2098       if (tmpcolumn == column)
2099         {
2100           GtkAllocation allocation;
2101           GdkRectangle invalid_rect;
2102
2103           gtk_widget_get_allocation (widget, &allocation);
2104           invalid_rect.x = column_offset;
2105           invalid_rect.y = 0;
2106           invalid_rect.width = column->width;
2107           invalid_rect.height = allocation.height;
2108
2109           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2110           break;
2111         }
2112       
2113       column_offset += tmpcolumn->width;
2114     }
2115 }
2116
2117 static void
2118 invalidate_last_column (GtkTreeView *tree_view)
2119 {
2120   GList *last_column;
2121   gboolean rtl;
2122
2123   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2124
2125   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2126        last_column;
2127        last_column = (rtl ? last_column->next : last_column->prev))
2128     {
2129       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2130         {
2131           invalidate_column (tree_view, last_column->data);
2132           return;
2133         }
2134     }
2135 }
2136
2137 static gint
2138 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2139                                                     GtkTreeViewColumn *column)
2140 {
2141   gint real_requested_width;
2142
2143   if (column->use_resized_width)
2144     {
2145       real_requested_width = column->resized_width;
2146     }
2147   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2148     {
2149       real_requested_width = column->fixed_width;
2150     }
2151   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2152     {
2153       real_requested_width = MAX (column->requested_width, column->button_request);
2154     }
2155   else
2156     {
2157       real_requested_width = column->requested_width;
2158       if (real_requested_width < 0)
2159         real_requested_width = 0;
2160     }
2161
2162   if (column->min_width != -1)
2163     real_requested_width = MAX (real_requested_width, column->min_width);
2164   if (column->max_width != -1)
2165     real_requested_width = MIN (real_requested_width, column->max_width);
2166
2167   return real_requested_width;
2168 }
2169
2170 /* GtkWidget::size_allocate helper */
2171 static void
2172 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2173                                      gboolean  *width_changed)
2174 {
2175   GtkTreeView *tree_view;
2176   GList *list, *first_column, *last_column;
2177   GtkTreeViewColumn *column;
2178   GtkAllocation allocation;
2179   GtkAllocation widget_allocation;
2180   gint width = 0;
2181   gint extra, extra_per_column, extra_for_last;
2182   gint full_requested_width = 0;
2183   gint number_of_expand_columns = 0;
2184   gboolean column_changed = FALSE;
2185   gboolean rtl;
2186   gboolean update_expand;
2187   
2188   tree_view = GTK_TREE_VIEW (widget);
2189
2190   for (last_column = g_list_last (tree_view->priv->columns);
2191        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2192        last_column = last_column->prev)
2193     ;
2194   if (last_column == NULL)
2195     return;
2196
2197   for (first_column = g_list_first (tree_view->priv->columns);
2198        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2199        first_column = first_column->next)
2200     ;
2201
2202   allocation.y = 0;
2203   allocation.height = tree_view->priv->header_height;
2204
2205   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2206
2207   /* find out how many extra space and expandable columns we have */
2208   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2209     {
2210       column = (GtkTreeViewColumn *)list->data;
2211
2212       if (!column->visible)
2213         continue;
2214
2215       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2216
2217       if (column->expand)
2218         number_of_expand_columns++;
2219     }
2220
2221   /* Only update the expand value if the width of the widget has changed,
2222    * or the number of expand columns has changed, or if there are no expand
2223    * columns, or if we didn't have an size-allocation yet after the
2224    * last validated node.
2225    */
2226   update_expand = (width_changed && *width_changed == TRUE)
2227       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2228       || number_of_expand_columns == 0
2229       || tree_view->priv->post_validation_flag == TRUE;
2230
2231   tree_view->priv->post_validation_flag = FALSE;
2232
2233   gtk_widget_get_allocation (widget, &widget_allocation);
2234   if (!update_expand)
2235     {
2236       extra = tree_view->priv->last_extra_space;
2237       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2238     }
2239   else
2240     {
2241       extra = MAX (widget_allocation.width - full_requested_width, 0);
2242       extra_for_last = 0;
2243
2244       tree_view->priv->last_extra_space = extra;
2245     }
2246
2247   if (number_of_expand_columns > 0)
2248     extra_per_column = extra/number_of_expand_columns;
2249   else
2250     extra_per_column = 0;
2251
2252   if (update_expand)
2253     {
2254       tree_view->priv->last_extra_space_per_column = extra_per_column;
2255       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2256     }
2257
2258   for (list = (rtl ? last_column : first_column); 
2259        list != (rtl ? first_column->prev : last_column->next);
2260        list = (rtl ? list->prev : list->next)) 
2261     {
2262       gint real_requested_width = 0;
2263       gint old_width;
2264
2265       column = list->data;
2266       old_width = column->width;
2267
2268       if (!column->visible)
2269         continue;
2270
2271       /* We need to handle the dragged button specially.
2272        */
2273       if (column == tree_view->priv->drag_column)
2274         {
2275           GtkAllocation drag_allocation;
2276
2277           drag_allocation.x = 0;
2278           drag_allocation.y = 0;
2279           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2280           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2281           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2282                                     &drag_allocation);
2283           width += drag_allocation.width;
2284           continue;
2285         }
2286
2287       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2288
2289       allocation.x = width;
2290       column->width = real_requested_width;
2291
2292       if (column->expand)
2293         {
2294           if (number_of_expand_columns == 1)
2295             {
2296               /* We add the remander to the last column as
2297                * */
2298               column->width += extra;
2299             }
2300           else
2301             {
2302               column->width += extra_per_column;
2303               extra -= extra_per_column;
2304               number_of_expand_columns --;
2305             }
2306         }
2307       else if (number_of_expand_columns == 0 &&
2308                list == last_column)
2309         {
2310           column->width += extra;
2311         }
2312
2313       /* In addition to expand, the last column can get even more
2314        * extra space so all available space is filled up.
2315        */
2316       if (extra_for_last > 0 && list == last_column)
2317         column->width += extra_for_last;
2318
2319       g_object_notify (G_OBJECT (column), "width");
2320
2321       allocation.width = column->width;
2322       width += column->width;
2323
2324       if (column->width > old_width)
2325         column_changed = TRUE;
2326
2327       gtk_widget_size_allocate (column->button, &allocation);
2328
2329       if (column->window)
2330         gdk_window_move_resize (column->window,
2331                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2332                                 allocation.y,
2333                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2334     }
2335
2336   /* We change the width here.  The user might have been resizing columns,
2337    * so the total width of the tree view changes.
2338    */
2339   tree_view->priv->width = width;
2340   if (width_changed)
2341     *width_changed = TRUE;
2342
2343   if (column_changed)
2344     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2345 }
2346
2347
2348 static void
2349 gtk_tree_view_size_allocate (GtkWidget     *widget,
2350                              GtkAllocation *allocation)
2351 {
2352   GtkAllocation widget_allocation;
2353   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2354   GList *tmp_list;
2355   gboolean width_changed = FALSE;
2356   gint old_width;
2357
2358   gtk_widget_get_allocation (widget, &widget_allocation);
2359   old_width = widget_allocation.width;
2360   if (allocation->width != widget_allocation.width)
2361     width_changed = TRUE;
2362
2363   gtk_widget_set_allocation (widget, allocation);
2364
2365   tmp_list = tree_view->priv->children;
2366
2367   while (tmp_list)
2368     {
2369       GtkAllocation allocation;
2370
2371       GtkTreeViewChild *child = tmp_list->data;
2372       tmp_list = tmp_list->next;
2373
2374       /* totally ignore our child's requisition */
2375       allocation.x = child->x;
2376       allocation.y = child->y;
2377       allocation.width = child->width;
2378       allocation.height = child->height;
2379       gtk_widget_size_allocate (child->widget, &allocation);
2380     }
2381
2382   /* We size-allocate the columns first because the width of the
2383    * tree view (used in updating the adjustments below) might change.
2384    */
2385   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2386
2387   tree_view->priv->hadjustment->page_size = allocation->width;
2388   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2389   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2390   tree_view->priv->hadjustment->lower = 0;
2391   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2392
2393   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2394     {
2395       if (allocation->width < tree_view->priv->width)
2396         {
2397           if (tree_view->priv->init_hadjust_value)
2398             {
2399               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2400               tree_view->priv->init_hadjust_value = FALSE;
2401             }
2402           else if (allocation->width != old_width)
2403             {
2404               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2405             }
2406           else
2407             tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
2408         }
2409       else
2410         {
2411           tree_view->priv->hadjustment->value = 0;
2412           tree_view->priv->init_hadjust_value = TRUE;
2413         }
2414     }
2415   else
2416     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2417       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2418
2419   gtk_adjustment_changed (tree_view->priv->hadjustment);
2420
2421   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2422   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2423   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2424   tree_view->priv->vadjustment->lower = 0;
2425   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2426
2427   gtk_adjustment_changed (tree_view->priv->vadjustment);
2428
2429   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2430   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2431     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2432   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2433     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2434                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2435   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2436     gtk_tree_view_top_row_to_dy (tree_view);
2437   else
2438     gtk_tree_view_dy_to_top_row (tree_view);
2439   
2440   if (gtk_widget_get_realized (widget))
2441     {
2442       gdk_window_move_resize (gtk_widget_get_window (widget),
2443                               allocation->x, allocation->y,
2444                               allocation->width, allocation->height);
2445       gdk_window_move_resize (tree_view->priv->header_window,
2446                               - (gint) tree_view->priv->hadjustment->value,
2447                               0,
2448                               MAX (tree_view->priv->width, allocation->width),
2449                               tree_view->priv->header_height);
2450       gdk_window_move_resize (tree_view->priv->bin_window,
2451                               - (gint) tree_view->priv->hadjustment->value,
2452                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2453                               MAX (tree_view->priv->width, allocation->width),
2454                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2455     }
2456
2457   if (tree_view->priv->tree == NULL)
2458     invalidate_empty_focus (tree_view);
2459
2460   if (gtk_widget_get_realized (widget))
2461     {
2462       gboolean has_expand_column = FALSE;
2463       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2464         {
2465           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2466             {
2467               has_expand_column = TRUE;
2468               break;
2469             }
2470         }
2471
2472       if (width_changed && tree_view->priv->expander_column)
2473         {
2474           /* Might seem awkward, but is the best heuristic I could come up
2475            * with.  Only if the width of the columns before the expander
2476            * changes, we will update the prelight status.  It is this
2477            * width that makes the expander move vertically.  Always updating
2478            * prelight status causes trouble with hover selections.
2479            */
2480           gint width_before_expander;
2481
2482           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2483
2484           if (tree_view->priv->prev_width_before_expander
2485               != width_before_expander)
2486               update_prelight (tree_view,
2487                                tree_view->priv->event_last_x,
2488                                tree_view->priv->event_last_y);
2489
2490           tree_view->priv->prev_width_before_expander = width_before_expander;
2491         }
2492
2493       /* This little hack only works if we have an LTR locale, and no column has the  */
2494       if (width_changed)
2495         {
2496           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2497               ! has_expand_column)
2498             invalidate_last_column (tree_view);
2499           else
2500             gtk_widget_queue_draw (widget);
2501         }
2502     }
2503 }
2504
2505 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2506 static void
2507 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2508 {
2509   GtkWidget *widget = GTK_WIDGET (tree_view);
2510
2511   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2512     gtk_widget_grab_focus (widget);
2513   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2514 }
2515
2516 static inline gboolean
2517 row_is_separator (GtkTreeView *tree_view,
2518                   GtkTreeIter *iter,
2519                   GtkTreePath *path)
2520 {
2521   gboolean is_separator = FALSE;
2522
2523   if (tree_view->priv->row_separator_func)
2524     {
2525       GtkTreeIter tmpiter;
2526
2527       if (iter)
2528         tmpiter = *iter;
2529       else
2530         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2531
2532       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2533                                                           &tmpiter,
2534                                                           tree_view->priv->row_separator_data);
2535     }
2536
2537   return is_separator;
2538 }
2539
2540 static gboolean
2541 gtk_tree_view_button_press (GtkWidget      *widget,
2542                             GdkEventButton *event)
2543 {
2544   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2545   GList *list;
2546   GtkTreeViewColumn *column = NULL;
2547   gint i;
2548   GdkRectangle background_area;
2549   GdkRectangle cell_area;
2550   gint vertical_separator;
2551   gint horizontal_separator;
2552   gboolean path_is_selectable;
2553   gboolean rtl;
2554
2555   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2556   gtk_tree_view_stop_editing (tree_view, FALSE);
2557   gtk_widget_style_get (widget,
2558                         "vertical-separator", &vertical_separator,
2559                         "horizontal-separator", &horizontal_separator,
2560                         NULL);
2561
2562
2563   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2564    * we're done handling the button press.
2565    */
2566
2567   if (event->window == tree_view->priv->bin_window)
2568     {
2569       GtkRBNode *node;
2570       GtkRBTree *tree;
2571       GtkTreePath *path;
2572       gchar *path_string;
2573       gint depth;
2574       gint new_y;
2575       gint y_offset;
2576       gint dval;
2577       gint pre_val, aft_val;
2578       GtkTreeViewColumn *column = NULL;
2579       GtkCellRenderer *focus_cell = NULL;
2580       gint column_handled_click = FALSE;
2581       gboolean row_double_click = FALSE;
2582       gboolean rtl;
2583       gboolean node_selected;
2584
2585       /* Empty tree? */
2586       if (tree_view->priv->tree == NULL)
2587         {
2588           grab_focus_and_unset_draw_keyfocus (tree_view);
2589           return TRUE;
2590         }
2591
2592       /* are we in an arrow? */
2593       if (tree_view->priv->prelight_node &&
2594           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2595           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2596         {
2597           if (event->button == 1)
2598             {
2599               gtk_grab_add (widget);
2600               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2601               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2602               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2603                                               tree_view->priv->prelight_tree,
2604                                               tree_view->priv->prelight_node);
2605             }
2606
2607           grab_focus_and_unset_draw_keyfocus (tree_view);
2608           return TRUE;
2609         }
2610
2611       /* find the node that was clicked */
2612       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2613       if (new_y < 0)
2614         new_y = 0;
2615       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2616
2617       if (node == NULL)
2618         {
2619           /* We clicked in dead space */
2620           grab_focus_and_unset_draw_keyfocus (tree_view);
2621           return TRUE;
2622         }
2623
2624       /* Get the path and the node */
2625       path = _gtk_tree_view_find_path (tree_view, tree, node);
2626       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2627
2628       if (!path_is_selectable)
2629         {
2630           gtk_tree_path_free (path);
2631           grab_focus_and_unset_draw_keyfocus (tree_view);
2632           return TRUE;
2633         }
2634
2635       depth = gtk_tree_path_get_depth (path);
2636       background_area.y = y_offset + event->y;
2637       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2638       background_area.x = 0;
2639
2640
2641       /* Let the column have a chance at selecting it. */
2642       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2643       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2644            list; list = (rtl ? list->prev : list->next))
2645         {
2646           GtkTreeViewColumn *candidate = list->data;
2647
2648           if (!candidate->visible)
2649             continue;
2650
2651           background_area.width = candidate->width;
2652           if ((background_area.x > (gint) event->x) ||
2653               (background_area.x + background_area.width <= (gint) event->x))
2654             {
2655               background_area.x += background_area.width;
2656               continue;
2657             }
2658
2659           /* we found the focus column */
2660           column = candidate;
2661           cell_area = background_area;
2662           cell_area.width -= horizontal_separator;
2663           cell_area.height -= vertical_separator;
2664           cell_area.x += horizontal_separator/2;
2665           cell_area.y += vertical_separator/2;
2666           if (gtk_tree_view_is_expander_column (tree_view, column))
2667             {
2668               if (!rtl)
2669                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2670               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2671
2672               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2673                 {
2674                   if (!rtl)
2675                     cell_area.x += depth * tree_view->priv->expander_size;
2676                   cell_area.width -= depth * tree_view->priv->expander_size;
2677                 }
2678             }
2679           break;
2680         }
2681
2682       if (column == NULL)
2683         {
2684           gtk_tree_path_free (path);
2685           grab_focus_and_unset_draw_keyfocus (tree_view);
2686           return FALSE;
2687         }
2688
2689       tree_view->priv->focus_column = column;
2690
2691       /* decide if we edit */
2692       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2693           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2694         {
2695           GtkTreePath *anchor;
2696           GtkTreeIter iter;
2697
2698           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2699           gtk_tree_view_column_cell_set_cell_data (column,
2700                                                    tree_view->priv->model,
2701                                                    &iter,
2702                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2703                                                    node->children?TRUE:FALSE);
2704
2705           if (tree_view->priv->anchor)
2706             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2707           else
2708             anchor = NULL;
2709
2710           if ((anchor && !gtk_tree_path_compare (anchor, path))
2711               || !_gtk_tree_view_column_has_editable_cell (column))
2712             {
2713               GtkCellEditable *cell_editable = NULL;
2714
2715               /* FIXME: get the right flags */
2716               guint flags = 0;
2717
2718               path_string = gtk_tree_path_to_string (path);
2719
2720               if (_gtk_tree_view_column_cell_event (column,
2721                                                     &cell_editable,
2722                                                     (GdkEvent *)event,
2723                                                     path_string,
2724                                                     &background_area,
2725                                                     &cell_area, flags))
2726                 {
2727                   if (cell_editable != NULL)
2728                     {
2729                       gint left, right;
2730                       GdkRectangle area;
2731
2732                       area = cell_area;
2733                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2734
2735                       area.x += left;
2736                       area.width -= right + left;
2737
2738                       gtk_tree_view_real_start_editing (tree_view,
2739                                                         column,
2740                                                         path,
2741                                                         cell_editable,
2742                                                         &area,
2743                                                         (GdkEvent *)event,
2744                                                         flags);
2745                       g_free (path_string);
2746                       gtk_tree_path_free (path);
2747                       gtk_tree_path_free (anchor);
2748                       return TRUE;
2749                     }
2750                   column_handled_click = TRUE;
2751                 }
2752               g_free (path_string);
2753             }
2754           if (anchor)
2755             gtk_tree_path_free (anchor);
2756         }
2757
2758       /* select */
2759       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2760       pre_val = tree_view->priv->vadjustment->value;
2761
2762       /* we only handle selection modifications on the first button press
2763        */
2764       if (event->type == GDK_BUTTON_PRESS)
2765         {
2766           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2767             tree_view->priv->ctrl_pressed = TRUE;
2768           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2769             tree_view->priv->shift_pressed = TRUE;
2770
2771           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2772           if (focus_cell)
2773             gtk_tree_view_column_focus_cell (column, focus_cell);
2774
2775           if (event->state & GDK_CONTROL_MASK)
2776             {
2777               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2778               gtk_tree_view_real_toggle_cursor_row (tree_view);
2779             }
2780           else if (event->state & GDK_SHIFT_MASK)
2781             {
2782               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2783               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2784             }
2785           else
2786             {
2787               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2788             }
2789
2790           tree_view->priv->ctrl_pressed = FALSE;
2791           tree_view->priv->shift_pressed = FALSE;
2792         }
2793
2794       /* the treeview may have been scrolled because of _set_cursor,
2795        * correct here
2796        */
2797
2798       aft_val = tree_view->priv->vadjustment->value;
2799       dval = pre_val - aft_val;
2800
2801       cell_area.y += dval;
2802       background_area.y += dval;
2803
2804       /* Save press to possibly begin a drag
2805        */
2806       if (!column_handled_click &&
2807           !tree_view->priv->in_grab &&
2808           tree_view->priv->pressed_button < 0)
2809         {
2810           tree_view->priv->pressed_button = event->button;
2811           tree_view->priv->press_start_x = event->x;
2812           tree_view->priv->press_start_y = event->y;
2813
2814           if (tree_view->priv->rubber_banding_enable
2815               && !node_selected
2816               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2817             {
2818               tree_view->priv->press_start_y += tree_view->priv->dy;
2819               tree_view->priv->rubber_band_x = event->x;
2820               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2821               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2822
2823               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2824                 tree_view->priv->rubber_band_ctrl = TRUE;
2825               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2826                 tree_view->priv->rubber_band_shift = TRUE;
2827             }
2828         }
2829
2830       /* Test if a double click happened on the same row. */
2831       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2832         {
2833           int double_click_time, double_click_distance;
2834
2835           g_object_get (gtk_settings_get_default (),
2836                         "gtk-double-click-time", &double_click_time,
2837                         "gtk-double-click-distance", &double_click_distance,
2838                         NULL);
2839
2840           /* Same conditions as _gdk_event_button_generate */
2841           if (tree_view->priv->last_button_x != -1 &&
2842               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2843               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2844               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2845             {
2846               /* We do no longer compare paths of this row and the
2847                * row clicked previously.  We use the double click
2848                * distance to decide whether this is a valid click,
2849                * allowing the mouse to slightly move over another row.
2850                */
2851               row_double_click = TRUE;
2852
2853               tree_view->priv->last_button_time = 0;
2854               tree_view->priv->last_button_x = -1;
2855               tree_view->priv->last_button_y = -1;
2856             }
2857           else
2858             {
2859               tree_view->priv->last_button_time = event->time;
2860               tree_view->priv->last_button_x = event->x;
2861               tree_view->priv->last_button_y = event->y;
2862             }
2863         }
2864
2865       if (row_double_click)
2866         {
2867           gtk_grab_remove (widget);
2868           gtk_tree_view_row_activated (tree_view, path, column);
2869
2870           if (tree_view->priv->pressed_button == event->button)
2871             tree_view->priv->pressed_button = -1;
2872         }
2873
2874       gtk_tree_path_free (path);
2875
2876       /* If we activated the row through a double click we don't want to grab
2877        * focus back, as moving focus to another widget is pretty common.
2878        */
2879       if (!row_double_click)
2880         grab_focus_and_unset_draw_keyfocus (tree_view);
2881
2882       return TRUE;
2883     }
2884
2885   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2886    */
2887   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2888     {
2889       column = list->data;
2890       if (event->window == column->window &&
2891           column->resizable &&
2892           column->window)
2893         {
2894           GtkAllocation button_allocation;
2895           gpointer drag_data;
2896
2897           if (event->type == GDK_2BUTTON_PRESS &&
2898               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2899             {
2900               column->use_resized_width = FALSE;
2901               _gtk_tree_view_column_autosize (tree_view, column);
2902               return TRUE;
2903             }
2904
2905           if (gdk_pointer_grab (column->window, FALSE,
2906                                 GDK_POINTER_MOTION_HINT_MASK |
2907                                 GDK_BUTTON1_MOTION_MASK |
2908                                 GDK_BUTTON_RELEASE_MASK,
2909                                 NULL, NULL, event->time))
2910             return FALSE;
2911
2912           gtk_grab_add (widget);
2913           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2914           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2915
2916           /* block attached dnd signal handler */
2917           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2918           if (drag_data)
2919             g_signal_handlers_block_matched (widget,
2920                                              G_SIGNAL_MATCH_DATA,
2921                                              0, 0, NULL, NULL,
2922                                              drag_data);
2923
2924           gtk_widget_get_allocation (column->button, &button_allocation);
2925           tree_view->priv->drag_pos = i;
2926           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
2927
2928           if (!gtk_widget_has_focus (widget))
2929             gtk_widget_grab_focus (widget);
2930
2931           return TRUE;
2932         }
2933     }
2934   return FALSE;
2935 }
2936
2937 /* GtkWidget::button_release_event helper */
2938 static gboolean
2939 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2940                                           GdkEventButton *event)
2941 {
2942   GtkTreeView *tree_view;
2943   GList *l;
2944   gboolean rtl;
2945
2946   tree_view = GTK_TREE_VIEW (widget);
2947
2948   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2949   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2950   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2951
2952   /* Move the button back */
2953   g_object_ref (tree_view->priv->drag_column->button);
2954   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2955   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2956   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2957   g_object_unref (tree_view->priv->drag_column->button);
2958   gtk_widget_queue_resize (widget);
2959   if (tree_view->priv->drag_column->resizable)
2960     {
2961       gdk_window_raise (tree_view->priv->drag_column->window);
2962       gdk_window_show (tree_view->priv->drag_column->window);
2963     }
2964   else
2965     gdk_window_hide (tree_view->priv->drag_column->window);
2966
2967   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2968
2969   if (rtl)
2970     {
2971       if (tree_view->priv->cur_reorder &&
2972           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2973         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2974                                          tree_view->priv->cur_reorder->right_column);
2975     }
2976   else
2977     {
2978       if (tree_view->priv->cur_reorder &&
2979           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2980         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2981                                          tree_view->priv->cur_reorder->left_column);
2982     }
2983   tree_view->priv->drag_column = NULL;
2984   gdk_window_hide (tree_view->priv->drag_window);
2985
2986   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2987     g_slice_free (GtkTreeViewColumnReorder, l->data);
2988   g_list_free (tree_view->priv->column_drag_info);
2989   tree_view->priv->column_drag_info = NULL;
2990   tree_view->priv->cur_reorder = NULL;
2991
2992   if (tree_view->priv->drag_highlight_window)
2993     gdk_window_hide (tree_view->priv->drag_highlight_window);
2994
2995   /* Reset our flags */
2996   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2997   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2998
2999   return TRUE;
3000 }
3001
3002 /* GtkWidget::button_release_event helper */
3003 static gboolean
3004 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3005                                             GdkEventButton *event)
3006 {
3007   GtkTreeView *tree_view;
3008   gpointer drag_data;
3009
3010   tree_view = GTK_TREE_VIEW (widget);
3011
3012   tree_view->priv->drag_pos = -1;
3013
3014   /* unblock attached dnd signal handler */
3015   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3016   if (drag_data)
3017     g_signal_handlers_unblock_matched (widget,
3018                                        G_SIGNAL_MATCH_DATA,
3019                                        0, 0, NULL, NULL,
3020                                        drag_data);
3021
3022   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3023   gtk_grab_remove (widget);
3024   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3025                               event->time);
3026   return TRUE;
3027 }
3028
3029 static gboolean
3030 gtk_tree_view_button_release (GtkWidget      *widget,
3031                               GdkEventButton *event)
3032 {
3033   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3034
3035   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3036     return gtk_tree_view_button_release_drag_column (widget, event);
3037
3038   if (tree_view->priv->rubber_band_status)
3039     gtk_tree_view_stop_rubber_band (tree_view);
3040
3041   if (tree_view->priv->pressed_button == event->button)
3042     tree_view->priv->pressed_button = -1;
3043
3044   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3045     return gtk_tree_view_button_release_column_resize (widget, event);
3046
3047   if (tree_view->priv->button_pressed_node == NULL)
3048     return FALSE;
3049
3050   if (event->button == 1)
3051     {
3052       gtk_grab_remove (widget);
3053       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3054           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3055         {
3056           GtkTreePath *path = NULL;
3057
3058           path = _gtk_tree_view_find_path (tree_view,
3059                                            tree_view->priv->button_pressed_tree,
3060                                            tree_view->priv->button_pressed_node);
3061           /* Actually activate the node */
3062           if (tree_view->priv->button_pressed_node->children == NULL)
3063             gtk_tree_view_real_expand_row (tree_view, path,
3064                                            tree_view->priv->button_pressed_tree,
3065                                            tree_view->priv->button_pressed_node,
3066                                            FALSE, TRUE);
3067           else
3068             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3069                                              tree_view->priv->button_pressed_tree,
3070                                              tree_view->priv->button_pressed_node, TRUE);
3071           gtk_tree_path_free (path);
3072         }
3073
3074       tree_view->priv->button_pressed_tree = NULL;
3075       tree_view->priv->button_pressed_node = NULL;
3076     }
3077
3078   return TRUE;
3079 }
3080
3081 static gboolean
3082 gtk_tree_view_grab_broken (GtkWidget          *widget,
3083                            GdkEventGrabBroken *event)
3084 {
3085   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3086
3087   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3088     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3089
3090   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3091     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3092
3093   return TRUE;
3094 }
3095
3096 #if 0
3097 static gboolean
3098 gtk_tree_view_configure (GtkWidget *widget,
3099                          GdkEventConfigure *event)
3100 {
3101   GtkTreeView *tree_view;
3102
3103   tree_view = GTK_TREE_VIEW (widget);
3104   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3105
3106   return FALSE;
3107 }
3108 #endif
3109
3110 /* GtkWidget::motion_event function set.
3111  */
3112
3113 static gboolean
3114 coords_are_over_arrow (GtkTreeView *tree_view,
3115                        GtkRBTree   *tree,
3116                        GtkRBNode   *node,
3117                        /* these are in bin window coords */
3118                        gint         x,
3119                        gint         y)
3120 {
3121   GdkRectangle arrow;
3122   gint x2;
3123
3124   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3125     return FALSE;
3126
3127   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3128     return FALSE;
3129
3130   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3131
3132   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3133
3134   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3135
3136   arrow.width = x2 - arrow.x;
3137
3138   return (x >= arrow.x &&
3139           x < (arrow.x + arrow.width) &&
3140           y >= arrow.y &&
3141           y < (arrow.y + arrow.height));
3142 }
3143
3144 static gboolean
3145 auto_expand_timeout (gpointer data)
3146 {
3147   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3148   GtkTreePath *path;
3149
3150   if (tree_view->priv->prelight_node)
3151     {
3152       path = _gtk_tree_view_find_path (tree_view,
3153                                        tree_view->priv->prelight_tree,
3154                                        tree_view->priv->prelight_node);   
3155
3156       if (tree_view->priv->prelight_node->children)
3157         gtk_tree_view_collapse_row (tree_view, path);
3158       else
3159         gtk_tree_view_expand_row (tree_view, path, FALSE);
3160
3161       gtk_tree_path_free (path);
3162     }
3163
3164   tree_view->priv->auto_expand_timeout = 0;
3165
3166   return FALSE;
3167 }
3168
3169 static void
3170 remove_auto_expand_timeout (GtkTreeView *tree_view)
3171 {
3172   if (tree_view->priv->auto_expand_timeout != 0)
3173     {
3174       g_source_remove (tree_view->priv->auto_expand_timeout);
3175       tree_view->priv->auto_expand_timeout = 0;
3176     }
3177 }
3178
3179 static void
3180 do_prelight (GtkTreeView *tree_view,
3181              GtkRBTree   *tree,
3182              GtkRBNode   *node,
3183              /* these are in bin_window coords */
3184              gint         x,
3185              gint         y)
3186 {
3187   if (tree_view->priv->prelight_tree == tree &&
3188       tree_view->priv->prelight_node == node)
3189     {
3190       /*  We are still on the same node,
3191           but we might need to take care of the arrow  */
3192
3193       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3194         {
3195           gboolean over_arrow;
3196           gboolean flag_set;
3197
3198           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3199           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3200                                              GTK_TREE_VIEW_ARROW_PRELIT);
3201
3202           if (over_arrow != flag_set)
3203             {
3204               if (over_arrow)
3205                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3206                                         GTK_TREE_VIEW_ARROW_PRELIT);
3207               else
3208                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3209                                           GTK_TREE_VIEW_ARROW_PRELIT);
3210
3211               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3212             }
3213         }
3214
3215       return;
3216     }
3217
3218   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3219     {
3220       /*  Unprelight the old node and arrow  */
3221
3222       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3223                              GTK_RBNODE_IS_PRELIT);
3224
3225       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3226           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3227         {
3228           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3229           
3230           gtk_tree_view_queue_draw_arrow (tree_view,
3231                                           tree_view->priv->prelight_tree,
3232                                           tree_view->priv->prelight_node);
3233         }
3234
3235       _gtk_tree_view_queue_draw_node (tree_view,
3236                                       tree_view->priv->prelight_tree,
3237                                       tree_view->priv->prelight_node,
3238                                       NULL);
3239     }
3240
3241
3242   if (tree_view->priv->hover_expand)
3243     remove_auto_expand_timeout (tree_view);
3244
3245   /*  Set the new prelight values  */
3246   tree_view->priv->prelight_node = node;
3247   tree_view->priv->prelight_tree = tree;
3248
3249   if (!node || !tree)
3250     return;
3251
3252   /*  Prelight the new node and arrow  */
3253
3254   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3255       && coords_are_over_arrow (tree_view, tree, node, x, y))
3256     {
3257       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3258
3259       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3260     }
3261
3262   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3263
3264   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3265
3266   if (tree_view->priv->hover_expand)
3267     {
3268       tree_view->priv->auto_expand_timeout = 
3269         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3270     }
3271 }
3272
3273 static void
3274 prelight_or_select (GtkTreeView *tree_view,
3275                     GtkRBTree   *tree,
3276                     GtkRBNode   *node,
3277                     /* these are in bin_window coords */
3278                     gint         x,
3279                     gint         y)
3280 {
3281   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3282   
3283   if (tree_view->priv->hover_selection &&
3284       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3285       !(tree_view->priv->edited_column &&
3286         tree_view->priv->edited_column->editable_widget))
3287     {
3288       if (node)
3289         {
3290           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3291             {
3292               GtkTreePath *path;
3293               
3294               path = _gtk_tree_view_find_path (tree_view, tree, node);
3295               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3296               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3297                 {
3298                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3299                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3300                 }
3301               gtk_tree_path_free (path);
3302             }
3303         }
3304
3305       else if (mode == GTK_SELECTION_SINGLE)
3306         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3307     }
3308
3309     do_prelight (tree_view, tree, node, x, y);
3310 }
3311
3312 static void
3313 ensure_unprelighted (GtkTreeView *tree_view)
3314 {
3315   do_prelight (tree_view,
3316                NULL, NULL,
3317                -1000, -1000); /* coords not possibly over an arrow */
3318
3319   g_assert (tree_view->priv->prelight_node == NULL);
3320 }
3321
3322 static void
3323 update_prelight (GtkTreeView *tree_view,
3324                  gint         x,
3325                  gint         y)
3326 {
3327   int new_y;
3328   GtkRBTree *tree;
3329   GtkRBNode *node;
3330
3331   if (tree_view->priv->tree == NULL)
3332     return;
3333
3334   if (x == -10000)
3335     {
3336       ensure_unprelighted (tree_view);
3337       return;
3338     }
3339
3340   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3341   if (new_y < 0)
3342     new_y = 0;
3343
3344   _gtk_rbtree_find_offset (tree_view->priv->tree,
3345                            new_y, &tree, &node);
3346
3347   if (node)
3348     prelight_or_select (tree_view, tree, node, x, y);
3349 }
3350
3351
3352
3353
3354 /* Our motion arrow is either a box (in the case of the original spot)
3355  * or an arrow.  It is expander_size wide.
3356  */
3357 /*
3358  * 11111111111111
3359  * 01111111111110
3360  * 00111111111100
3361  * 00011111111000
3362  * 00001111110000
3363  * 00000111100000
3364  * 00000111100000
3365  * 00000111100000
3366  * ~ ~ ~ ~ ~ ~ ~
3367  * 00000111100000
3368  * 00000111100000
3369  * 00000111100000
3370  * 00001111110000
3371  * 00011111111000
3372  * 00111111111100
3373  * 01111111111110
3374  * 11111111111111
3375  */
3376
3377 static void
3378 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3379 {
3380   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3381   GtkWidget *widget = GTK_WIDGET (tree_view);
3382   cairo_surface_t *mask_image;
3383   cairo_region_t *mask_region;
3384   gint x;
3385   gint y;
3386   gint width;
3387   gint height;
3388   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3389   GdkWindowAttr attributes;
3390   guint attributes_mask;
3391   cairo_t *cr;
3392
3393   if (!reorder ||
3394       reorder->left_column == tree_view->priv->drag_column ||
3395       reorder->right_column == tree_view->priv->drag_column)
3396     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3397   else if (reorder->left_column || reorder->right_column)
3398     {
3399       GtkAllocation left_allocation, right_allocation;
3400       GdkRectangle visible_rect;
3401
3402       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3403       if (reorder->left_column)
3404         {
3405           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3406           x = left_allocation.x + left_allocation.width;
3407         }
3408       else
3409         {
3410           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3411           x = right_allocation.x;
3412         }
3413
3414       if (x < visible_rect.x)
3415         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3416       else if (x > visible_rect.x + visible_rect.width)
3417         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3418       else
3419         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3420     }
3421
3422   /* We want to draw the rectangle over the initial location. */
3423   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3424     {
3425       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3426         {
3427           GtkAllocation drag_allocation;
3428
3429           if (tree_view->priv->drag_highlight_window)
3430             {
3431               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3432                                         NULL);
3433               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3434             }
3435
3436           attributes.window_type = GDK_WINDOW_CHILD;
3437           attributes.wclass = GDK_INPUT_OUTPUT;
3438           attributes.x = tree_view->priv->drag_column_x;
3439           attributes.y = 0;
3440           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3441           width = attributes.width = drag_allocation.width;
3442           height = attributes.height = drag_allocation.height;
3443           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3444           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3445           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3446           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3447           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3448
3449           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3450           cr = cairo_create (mask_image);
3451
3452           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3453           cairo_stroke (cr);
3454           cairo_destroy (cr);
3455
3456           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3457           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3458                                            mask_region, 0, 0);
3459
3460           cairo_region_destroy (mask_region);
3461           cairo_surface_destroy (mask_image);
3462
3463           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3464         }
3465     }
3466   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3467     {
3468       GtkAllocation button_allocation;
3469
3470       width = tree_view->priv->expander_size;
3471
3472       /* Get x, y, width, height of arrow */
3473       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3474       if (reorder->left_column)
3475         {
3476           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3477           x += button_allocation.x + button_allocation.width - width/2;
3478           height = button_allocation.height;
3479         }
3480       else
3481         {
3482           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3483           x += button_allocation.x - width/2;
3484           height = button_allocation.height;
3485         }
3486       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3487       height += tree_view->priv->expander_size;
3488
3489       /* Create the new window */
3490       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3491         {
3492           if (tree_view->priv->drag_highlight_window)
3493             {
3494               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3495                                         NULL);
3496               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3497             }
3498
3499           attributes.window_type = GDK_WINDOW_TEMP;
3500           attributes.wclass = GDK_INPUT_OUTPUT;
3501           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3502           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3503           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3504           attributes.x = x;
3505           attributes.y = y;
3506           attributes.width = width;
3507           attributes.height = height;
3508           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3509                                                                    &attributes, attributes_mask);
3510           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3511
3512           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3513
3514           cr = cairo_create (mask_image);
3515           cairo_move_to (cr, 0, 0);
3516           cairo_line_to (cr, width, 0);
3517           cairo_line_to (cr, width / 2., width / 2);
3518           cairo_move_to (cr, 0, height);
3519           cairo_line_to (cr, width, height);
3520           cairo_line_to (cr, width / 2., height - width / 2.);
3521           cairo_fill (cr);
3522           cairo_destroy (cr);
3523
3524           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3525           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3526                                            mask_region, 0, 0);
3527
3528           cairo_region_destroy (mask_region);
3529           cairo_surface_destroy (mask_image);
3530         }
3531
3532       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3533       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3534     }
3535   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3536            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3537     {
3538       GtkAllocation allocation;
3539
3540       width = tree_view->priv->expander_size;
3541
3542       /* Get x, y, width, height of arrow */
3543       width = width/2; /* remember, the arrow only takes half the available width */
3544       gdk_window_get_origin (gtk_widget_get_window (widget),
3545                              &x, &y);
3546       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3547         {
3548           gtk_widget_get_allocation (widget, &allocation);
3549           x += allocation.width - width;
3550         }
3551
3552       if (reorder->left_column)
3553         {
3554           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3555           height = allocation.height;
3556         }
3557       else
3558         {
3559           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3560           height = allocation.height;
3561         }
3562
3563       y -= tree_view->priv->expander_size;
3564       height += 2*tree_view->priv->expander_size;
3565
3566       /* Create the new window */
3567       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3568           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3569         {
3570           if (tree_view->priv->drag_highlight_window)
3571             {
3572               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3573                                         NULL);
3574               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3575             }
3576
3577           attributes.window_type = GDK_WINDOW_TEMP;
3578           attributes.wclass = GDK_INPUT_OUTPUT;
3579           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3580           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3581           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3582           attributes.x = x;
3583           attributes.y = y;
3584           attributes.width = width;
3585           attributes.height = height;
3586           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3587           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3588
3589           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3590
3591           cr = cairo_create (mask_image);
3592           /* mirror if we're on the left */
3593           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3594             {
3595               cairo_translate (cr, width, 0);
3596               cairo_scale (cr, -1, 1);
3597             }
3598           cairo_move_to (cr, 0, 0);
3599           cairo_line_to (cr, width, width);
3600           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3601           cairo_move_to (cr, 0, height);
3602           cairo_line_to (cr, width, height - width);
3603           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3604           cairo_fill (cr);
3605           cairo_destroy (cr);
3606
3607           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3608           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3609                                            mask_region, 0, 0);
3610
3611           cairo_region_destroy (mask_region);
3612           cairo_surface_destroy (mask_image);
3613         }
3614
3615       tree_view->priv->drag_column_window_state = arrow_type;
3616       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3617    }
3618   else
3619     {
3620       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3621       gdk_window_hide (tree_view->priv->drag_highlight_window);
3622       return;
3623     }
3624
3625   gdk_window_show (tree_view->priv->drag_highlight_window);
3626   gdk_window_raise (tree_view->priv->drag_highlight_window);
3627 }
3628
3629 static gboolean
3630 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3631                                     GdkEventMotion *event)
3632 {
3633   gint x;
3634   gint new_width;
3635   GtkTreeViewColumn *column;
3636   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3637
3638   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3639
3640   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3641     gtk_widget_get_pointer (widget, &x, NULL);
3642   else
3643     x = event->x;
3644
3645   if (tree_view->priv->hadjustment)
3646     x += tree_view->priv->hadjustment->value;
3647
3648   new_width = gtk_tree_view_new_column_width (tree_view,
3649                                               tree_view->priv->drag_pos, &x);
3650   if (x != tree_view->priv->x_drag &&
3651       (new_width != column->fixed_width))
3652     {
3653       column->use_resized_width = TRUE;
3654       column->resized_width = new_width;
3655       if (column->expand)
3656         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3657       gtk_widget_queue_resize (widget);
3658     }
3659
3660   return FALSE;
3661 }
3662
3663
3664 static void
3665 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3666 {
3667   GtkTreeViewColumnReorder *reorder = NULL;
3668   GList *list;
3669   gint mouse_x;
3670
3671   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3672   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3673     {
3674       reorder = (GtkTreeViewColumnReorder *) list->data;
3675       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3676         break;
3677       reorder = NULL;
3678     }
3679
3680   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3681       return;*/
3682
3683   tree_view->priv->cur_reorder = reorder;
3684   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3685 }
3686
3687 static void
3688 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3689 {
3690   GdkRectangle visible_rect;
3691   gint y;
3692   gint offset;
3693
3694   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3695   y += tree_view->priv->dy;
3696
3697   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3698
3699   /* see if we are near the edge. */
3700   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3701   if (offset > 0)
3702     {
3703       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3704       if (offset < 0)
3705         return;
3706     }
3707
3708   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3709                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3710 }
3711
3712 static gboolean
3713 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3714 {
3715   GdkRectangle visible_rect;
3716   gint x;
3717   gint offset;
3718
3719   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3720
3721   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3722
3723   /* See if we are near the edge. */
3724   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3725   if (offset > 0)
3726     {
3727       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3728       if (offset < 0)
3729         return TRUE;
3730     }
3731   offset = offset/3;
3732
3733   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3734                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3735
3736   return TRUE;
3737
3738 }
3739
3740 static gboolean
3741 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3742                                   GdkEventMotion *event)
3743 {
3744   GtkAllocation allocation, button_allocation;
3745   GtkTreeView *tree_view = (GtkTreeView *) widget;
3746   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3747   gint x, y;
3748
3749   /* Sanity Check */
3750   if ((column == NULL) ||
3751       (event->window != tree_view->priv->drag_window))
3752     return FALSE;
3753
3754   /* Handle moving the header */
3755   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3756   gtk_widget_get_allocation (widget, &allocation);
3757   gtk_widget_get_allocation (column->button, &button_allocation);
3758   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3759              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3760   gdk_window_move (tree_view->priv->drag_window, x, y);
3761   
3762   /* autoscroll, if needed */
3763   gtk_tree_view_horizontal_autoscroll (tree_view);
3764   /* Update the current reorder position and arrow; */
3765   gtk_tree_view_update_current_reorder (tree_view);
3766
3767   return TRUE;
3768 }
3769
3770 static void
3771 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3772 {
3773   remove_scroll_timeout (tree_view);
3774   gtk_grab_remove (GTK_WIDGET (tree_view));
3775
3776   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3777     {
3778       GtkTreePath *tmp_path;
3779
3780       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3781
3782       /* The anchor path should be set to the start path */
3783       tmp_path = _gtk_tree_view_find_path (tree_view,
3784                                            tree_view->priv->rubber_band_start_tree,
3785                                            tree_view->priv->rubber_band_start_node);
3786
3787       if (tree_view->priv->anchor)
3788         gtk_tree_row_reference_free (tree_view->priv->anchor);
3789
3790       tree_view->priv->anchor =
3791         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3792                                           tree_view->priv->model,
3793                                           tmp_path);
3794
3795       gtk_tree_path_free (tmp_path);
3796
3797       /* ... and the cursor to the end path */
3798       tmp_path = _gtk_tree_view_find_path (tree_view,
3799                                            tree_view->priv->rubber_band_end_tree,
3800                                            tree_view->priv->rubber_band_end_node);
3801       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3802       gtk_tree_path_free (tmp_path);
3803
3804       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3805     }
3806
3807   /* Clear status variables */
3808   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3809   tree_view->priv->rubber_band_shift = 0;
3810   tree_view->priv->rubber_band_ctrl = 0;
3811
3812   tree_view->priv->rubber_band_start_node = NULL;
3813   tree_view->priv->rubber_band_start_tree = NULL;
3814   tree_view->priv->rubber_band_end_node = NULL;
3815   tree_view->priv->rubber_band_end_tree = NULL;
3816 }
3817
3818 static void
3819 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3820                                                  GtkRBTree   *start_tree,
3821                                                  GtkRBNode   *start_node,
3822                                                  GtkRBTree   *end_tree,
3823                                                  GtkRBNode   *end_node,
3824                                                  gboolean     select,
3825                                                  gboolean     skip_start,
3826                                                  gboolean     skip_end)
3827 {
3828   if (start_node == end_node)
3829     return;
3830
3831   /* We skip the first node and jump inside the loop */
3832   if (skip_start)
3833     goto skip_first;
3834
3835   do
3836     {
3837       /* Small optimization by assuming insensitive nodes are never
3838        * selected.
3839        */
3840       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3841         {
3842           GtkTreePath *path;
3843           gboolean selectable;
3844
3845           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3846           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3847           gtk_tree_path_free (path);
3848
3849           if (!selectable)
3850             goto node_not_selectable;
3851         }
3852
3853       if (select)
3854         {
3855           if (tree_view->priv->rubber_band_shift)
3856             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3857           else if (tree_view->priv->rubber_band_ctrl)
3858             {
3859               /* Toggle the selection state */
3860               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3861                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3862               else
3863                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3864             }
3865           else
3866             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3867         }
3868       else
3869         {
3870           /* Mirror the above */
3871           if (tree_view->priv->rubber_band_shift)
3872             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3873           else if (tree_view->priv->rubber_band_ctrl)
3874             {
3875               /* Toggle the selection state */
3876               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3877                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3878               else
3879                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3880             }
3881           else
3882             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3883         }
3884
3885       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3886
3887 node_not_selectable:
3888       if (start_node == end_node)
3889         break;
3890
3891 skip_first:
3892
3893       if (start_node->children)
3894         {
3895           start_tree = start_node->children;
3896           start_node = start_tree->root;
3897           while (start_node->left != start_tree->nil)
3898             start_node = start_node->left;
3899         }
3900       else
3901         {
3902           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3903
3904           if (!start_tree)
3905             /* Ran out of tree */
3906             break;
3907         }
3908
3909       if (skip_end && start_node == end_node)
3910         break;
3911     }
3912   while (TRUE);
3913 }
3914
3915 static void
3916 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3917 {
3918   GtkRBTree *start_tree, *end_tree;
3919   GtkRBNode *start_node, *end_node;
3920
3921   _gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node);
3922   _gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node);
3923
3924   /* Handle the start area first */
3925   if (!tree_view->priv->rubber_band_start_node)
3926     {
3927       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3928                                                        start_tree,
3929                                                        start_node,
3930                                                        end_tree,
3931                                                        end_node,
3932                                                        TRUE,
3933                                                        FALSE,
3934                                                        FALSE);
3935     }
3936   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3937            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3938     {
3939       /* New node is above the old one; selection became bigger */
3940       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3941                                                        start_tree,
3942                                                        start_node,
3943                                                        tree_view->priv->rubber_band_start_tree,
3944                                                        tree_view->priv->rubber_band_start_node,
3945                                                        TRUE,
3946                                                        FALSE,
3947                                                        TRUE);
3948     }
3949   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3950            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3951     {
3952       /* New node is below the old one; selection became smaller */
3953       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3954                                                        tree_view->priv->rubber_band_start_tree,
3955                                                        tree_view->priv->rubber_band_start_node,
3956                                                        start_tree,
3957                                                        start_node,
3958                                                        FALSE,
3959                                                        FALSE,
3960                                                        TRUE);
3961     }
3962
3963   tree_view->priv->rubber_band_start_tree = start_tree;
3964   tree_view->priv->rubber_band_start_node = start_node;
3965
3966   /* Next, handle the end area */
3967   if (!tree_view->priv->rubber_band_end_node)
3968     {
3969       /* In the event this happens, start_node was also NULL; this case is
3970        * handled above.
3971        */
3972     }
3973   else if (!end_node)
3974     {
3975       /* Find the last node in the tree */
3976       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3977                                &end_tree, &end_node);
3978
3979       /* Selection reached end of the tree */
3980       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3981                                                        tree_view->priv->rubber_band_end_tree,
3982                                                        tree_view->priv->rubber_band_end_node,
3983                                                        end_tree,
3984                                                        end_node,
3985                                                        TRUE,
3986                                                        TRUE,
3987                                                        FALSE);
3988     }
3989   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3990            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3991     {
3992       /* New node is below the old one; selection became bigger */
3993       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3994                                                        tree_view->priv->rubber_band_end_tree,
3995                                                        tree_view->priv->rubber_band_end_node,
3996                                                        end_tree,
3997                                                        end_node,
3998                                                        TRUE,
3999                                                        TRUE,
4000                                                        FALSE);
4001     }
4002   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4003            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4004     {
4005       /* New node is above the old one; selection became smaller */
4006       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4007                                                        end_tree,
4008                                                        end_node,
4009                                                        tree_view->priv->rubber_band_end_tree,
4010                                                        tree_view->priv->rubber_band_end_node,
4011                                                        FALSE,
4012                                                        TRUE,
4013                                                        FALSE);
4014     }
4015
4016   tree_view->priv->rubber_band_end_tree = end_tree;
4017   tree_view->priv->rubber_band_end_node = end_node;
4018 }
4019
4020 static void
4021 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4022 {
4023   gint x, y;
4024   GdkRectangle old_area;
4025   GdkRectangle new_area;
4026   GdkRectangle common;
4027   cairo_region_t *invalid_region;
4028
4029   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4030   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4031   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4032   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4033
4034   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4035
4036   x = MAX (x, 0);
4037   y = MAX (y, 0) + tree_view->priv->dy;
4038
4039   new_area.x = MIN (tree_view->priv->press_start_x, x);
4040   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4041   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4042   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4043
4044   invalid_region = cairo_region_create_rectangle (&old_area);
4045   cairo_region_union_rectangle (invalid_region, &new_area);
4046
4047   gdk_rectangle_intersect (&old_area, &new_area, &common);
4048   if (common.width > 2 && common.height > 2)
4049     {
4050       cairo_region_t *common_region;
4051
4052       /* make sure the border is invalidated */
4053       common.x += 1;
4054       common.y += 1;
4055       common.width -= 2;
4056       common.height -= 2;
4057
4058       common_region = cairo_region_create_rectangle (&common);
4059
4060       cairo_region_subtract (invalid_region, common_region);
4061       cairo_region_destroy (common_region);
4062     }
4063
4064   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4065
4066   cairo_region_destroy (invalid_region);
4067
4068   tree_view->priv->rubber_band_x = x;
4069   tree_view->priv->rubber_band_y = y;
4070
4071   gtk_tree_view_update_rubber_band_selection (tree_view);
4072 }
4073
4074 static void
4075 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4076                                  cairo_t      *cr)
4077 {
4078   GdkRectangle rect;
4079   GtkStyle *style;
4080
4081   cairo_save (cr);
4082
4083   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4084   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4085   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4086   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4087
4088   cairo_set_line_width (cr, 1.0);
4089
4090   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4091
4092   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4093
4094   gdk_cairo_rectangle (cr, &rect);
4095   cairo_clip (cr);
4096   cairo_paint_with_alpha (cr, 0.25);
4097
4098   cairo_rectangle (cr,
4099                    rect.x + 0.5, rect.y + 0.5,
4100                    rect.width - 1, rect.height - 1);
4101   cairo_stroke (cr);
4102
4103   cairo_restore (cr);
4104 }
4105
4106 static gboolean
4107 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4108                                  GdkEventMotion *event)
4109 {
4110   GtkTreeView *tree_view;
4111   GtkRBTree *tree;
4112   GtkRBNode *node;
4113   gint new_y;
4114
4115   tree_view = (GtkTreeView *) widget;
4116
4117   if (tree_view->priv->tree == NULL)
4118     return FALSE;
4119
4120   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4121     {
4122       gtk_grab_add (GTK_WIDGET (tree_view));
4123       gtk_tree_view_update_rubber_band (tree_view);
4124
4125       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4126     }
4127   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4128     {
4129       gtk_tree_view_update_rubber_band (tree_view);
4130
4131       add_scroll_timeout (tree_view);
4132     }
4133
4134   /* only check for an initiated drag when a button is pressed */
4135   if (tree_view->priv->pressed_button >= 0
4136       && !tree_view->priv->rubber_band_status)
4137     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4138
4139   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4140   if (new_y < 0)
4141     new_y = 0;
4142
4143   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4144
4145   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4146   if ((tree_view->priv->button_pressed_node != NULL) &&
4147       (tree_view->priv->button_pressed_node != node))
4148     node = NULL;
4149
4150   tree_view->priv->event_last_x = event->x;
4151   tree_view->priv->event_last_y = event->y;
4152
4153   prelight_or_select (tree_view, tree, node, event->x, event->y);
4154
4155   return TRUE;
4156 }
4157
4158 static gboolean
4159 gtk_tree_view_motion (GtkWidget      *widget,
4160                       GdkEventMotion *event)
4161 {
4162   GtkTreeView *tree_view;
4163
4164   tree_view = (GtkTreeView *) widget;
4165
4166   /* Resizing a column */
4167   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4168     return gtk_tree_view_motion_resize_column (widget, event);
4169
4170   /* Drag column */
4171   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4172     return gtk_tree_view_motion_drag_column (widget, event);
4173
4174   /* Sanity check it */
4175   if (event->window == tree_view->priv->bin_window)
4176     return gtk_tree_view_motion_bin_window (widget, event);
4177
4178   return FALSE;
4179 }
4180
4181 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4182  * the tree is empty.
4183  */
4184 static void
4185 invalidate_empty_focus (GtkTreeView *tree_view)
4186 {
4187   GdkRectangle area;
4188
4189   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4190     return;
4191
4192   area.x = 0;
4193   area.y = 0;
4194   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4195   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4196   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4197 }
4198
4199 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4200  * is empty.
4201  */
4202 static void
4203 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4204 {
4205   GtkWidget *widget = GTK_WIDGET (tree_view);
4206   gint w, h;
4207
4208   if (!gtk_widget_has_focus (widget))
4209     return;
4210
4211   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4212   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4213
4214   if (w > 0 && h > 0)
4215     gtk_paint_focus (gtk_widget_get_style (widget),
4216                      cr,
4217                      gtk_widget_get_state (widget),
4218                      widget,
4219                      NULL,
4220                      1, 1, w, h);
4221 }
4222
4223 typedef enum {
4224   GTK_TREE_VIEW_GRID_LINE,
4225   GTK_TREE_VIEW_TREE_LINE,
4226   GTK_TREE_VIEW_FOREGROUND_LINE
4227 } GtkTreeViewLineType;
4228
4229 static void
4230 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4231                          cairo_t             *cr,
4232                          GtkTreeViewLineType  type,
4233                          int                  x1,
4234                          int                  y1,
4235                          int                  x2,
4236                          int                  y2)
4237 {
4238   cairo_save (cr);
4239
4240   switch (type)
4241     {
4242     case GTK_TREE_VIEW_TREE_LINE:
4243       cairo_set_source_rgb (cr, 0, 0, 0);
4244       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4245       if (tree_view->priv->tree_line_dashes[0])
4246         cairo_set_dash (cr, 
4247                         tree_view->priv->tree_line_dashes,
4248                         2, 0.5);
4249       break;
4250     case GTK_TREE_VIEW_GRID_LINE:
4251       cairo_set_source_rgb (cr, 0, 0, 0);
4252       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4253       if (tree_view->priv->grid_line_dashes[0])
4254         cairo_set_dash (cr, 
4255                         tree_view->priv->grid_line_dashes,
4256                         2, 0.5);
4257       break;
4258     default:
4259       g_assert_not_reached ();
4260       /* fall through */
4261     case GTK_TREE_VIEW_FOREGROUND_LINE:
4262       cairo_set_line_width (cr, 1.0);
4263       gdk_cairo_set_source_color (cr,
4264                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4265       break;
4266     }
4267
4268   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4269   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4270   cairo_stroke (cr);
4271
4272   cairo_restore (cr);
4273 }
4274                          
4275 static void
4276 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4277                                cairo_t        *cr,
4278                                gint            n_visible_columns)
4279 {
4280   GList *list = tree_view->priv->columns;
4281   gint i = 0;
4282   gint current_x = 0;
4283
4284   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4285       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4286     return;
4287
4288   /* Only draw the lines for visible rows and columns */
4289   for (list = tree_view->priv->columns; list; list = list->next, i++)
4290     {
4291       GtkTreeViewColumn *column = list->data;
4292
4293       /* We don't want a line for the last column */
4294       if (i == n_visible_columns - 1)
4295         break;
4296
4297       if (! column->visible)
4298         continue;
4299
4300       current_x += column->width;
4301
4302       gtk_tree_view_draw_line (tree_view, cr,
4303                                GTK_TREE_VIEW_GRID_LINE,
4304                                current_x - 1, 0,
4305                                current_x - 1, tree_view->priv->height);
4306     }
4307 }
4308
4309 /* Warning: Very scary function.
4310  * Modify at your own risk
4311  *
4312  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4313  * FIXME: It's not...
4314  */
4315 static gboolean
4316 gtk_tree_view_bin_draw (GtkWidget      *widget,
4317                         cairo_t        *cr)
4318 {
4319   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4320   GtkTreePath *path;
4321   GtkStyle *style;
4322   GtkRBTree *tree;
4323   GList *list;
4324   GtkRBNode *node;
4325   GtkRBNode *cursor = NULL;
4326   GtkRBTree *cursor_tree = NULL;
4327   GtkRBNode *drag_highlight = NULL;
4328   GtkRBTree *drag_highlight_tree = NULL;
4329   GtkTreeIter iter;
4330   gint new_y;
4331   gint y_offset, cell_offset;
4332   gint max_height;
4333   gint depth;
4334   GdkRectangle background_area;
4335   GdkRectangle cell_area;
4336   GdkRectangle clip;
4337   guint flags;
4338   gint highlight_x;
4339   gint expander_cell_width;
4340   gint bin_window_width;
4341   gint bin_window_height;
4342   GtkTreePath *cursor_path;
4343   GtkTreePath *drag_dest_path;
4344   GList *first_column, *last_column;
4345   gint vertical_separator;
4346   gint horizontal_separator;
4347   gint focus_line_width;
4348   gboolean allow_rules;
4349   gboolean has_special_cell;
4350   gboolean rtl;
4351   gint n_visible_columns;
4352   gint pointer_x, pointer_y;
4353   gint grid_line_width;
4354   gboolean got_pointer = FALSE;
4355   gboolean draw_vgrid_lines, draw_hgrid_lines;
4356
4357   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4358
4359   gtk_widget_style_get (widget,
4360                         "horizontal-separator", &horizontal_separator,
4361                         "vertical-separator", &vertical_separator,
4362                         "allow-rules", &allow_rules,
4363                         "focus-line-width", &focus_line_width,
4364                         NULL);
4365
4366   if (tree_view->priv->tree == NULL)
4367     {
4368       draw_empty_focus (tree_view, cr);
4369       return TRUE;
4370     }
4371
4372   validate_visible_area (tree_view);
4373
4374   style = gtk_widget_get_style (widget);
4375
4376   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4377   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4378   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4379   cairo_clip (cr);
4380   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4381     return TRUE;
4382
4383   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4384
4385   if (new_y < 0)
4386     new_y = 0;
4387   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4388
4389   if (tree_view->priv->height < bin_window_height)
4390     {
4391       gtk_paint_flat_box (style,
4392                           cr,
4393                           gtk_widget_get_state (widget),
4394                           GTK_SHADOW_NONE,
4395                           widget,
4396                           "cell_even",
4397                           0, tree_view->priv->height,
4398                           bin_window_width,
4399                           bin_window_height - tree_view->priv->height);
4400     }
4401
4402   if (node == NULL)
4403     return TRUE;
4404
4405   /* find the path for the node */
4406   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4407                                    tree,
4408                                    node);
4409   gtk_tree_model_get_iter (tree_view->priv->model,
4410                            &iter,
4411                            path);
4412   depth = gtk_tree_path_get_depth (path);
4413   gtk_tree_path_free (path);
4414   
4415   cursor_path = NULL;
4416   drag_dest_path = NULL;
4417
4418   if (tree_view->priv->cursor)
4419     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4420
4421   if (cursor_path)
4422     _gtk_tree_view_find_node (tree_view, cursor_path,
4423                               &cursor_tree, &cursor);
4424
4425   if (tree_view->priv->drag_dest_row)
4426     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4427
4428   if (drag_dest_path)
4429     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4430                               &drag_highlight_tree, &drag_highlight);
4431
4432   draw_vgrid_lines =
4433     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4434     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4435   draw_hgrid_lines =
4436     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4437     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4438
4439   if (draw_vgrid_lines || draw_hgrid_lines)
4440     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4441   
4442   n_visible_columns = 0;
4443   for (list = tree_view->priv->columns; list; list = list->next)
4444     {
4445       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4446         continue;
4447       n_visible_columns ++;
4448     }
4449
4450   /* Find the last column */
4451   for (last_column = g_list_last (tree_view->priv->columns);
4452        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4453        last_column = last_column->prev)
4454     ;
4455
4456   /* and the first */
4457   for (first_column = g_list_first (tree_view->priv->columns);
4458        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4459        first_column = first_column->next)
4460     ;
4461
4462   /* Actually process the expose event.  To do this, we want to
4463    * start at the first node of the event, and walk the tree in
4464    * order, drawing each successive node.
4465    */
4466
4467   do
4468     {
4469       gboolean parity;
4470       gboolean is_separator = FALSE;
4471       gboolean is_first = FALSE;
4472       gboolean is_last = FALSE;
4473       
4474       is_separator = row_is_separator (tree_view, &iter, NULL);
4475
4476       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4477
4478       cell_offset = 0;
4479       highlight_x = 0; /* should match x coord of first cell */
4480       expander_cell_width = 0;
4481
4482       background_area.y = y_offset + clip.y;
4483       background_area.height = max_height;
4484
4485       flags = 0;
4486
4487       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4488         flags |= GTK_CELL_RENDERER_PRELIT;
4489
4490       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4491         flags |= GTK_CELL_RENDERER_SELECTED;
4492
4493       parity = _gtk_rbtree_node_find_parity (tree, node);
4494
4495       /* we *need* to set cell data on all cells before the call
4496        * to _has_special_cell, else _has_special_cell() does not
4497        * return a correct value.
4498        */
4499       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4500            list;
4501            list = (rtl ? list->prev : list->next))
4502         {
4503           GtkTreeViewColumn *column = list->data;
4504           gtk_tree_view_column_cell_set_cell_data (column,
4505                                                    tree_view->priv->model,
4506                                                    &iter,
4507                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4508                                                    node->children?TRUE:FALSE);
4509         }
4510
4511       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4512
4513       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4514            list;
4515            list = (rtl ? list->prev : list->next))
4516         {
4517           GtkTreeViewColumn *column = list->data;
4518           const gchar *detail = NULL;
4519           gchar new_detail[128];
4520           GtkStateType state;
4521
4522           if (!column->visible)
4523             continue;
4524
4525           if (cell_offset > clip.x + clip.width ||
4526               cell_offset + column->width < clip.x)
4527             {
4528               cell_offset += column->width;
4529               continue;
4530             }
4531
4532           if (column->show_sort_indicator)
4533             flags |= GTK_CELL_RENDERER_SORTED;
4534           else
4535             flags &= ~GTK_CELL_RENDERER_SORTED;
4536
4537           if (cursor == node)
4538             flags |= GTK_CELL_RENDERER_FOCUSED;
4539           else
4540             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4541
4542           background_area.x = cell_offset;
4543           background_area.width = column->width;
4544
4545           cell_area = background_area;
4546           cell_area.y += vertical_separator / 2;
4547           cell_area.x += horizontal_separator / 2;
4548           cell_area.height -= vertical_separator;
4549           cell_area.width -= horizontal_separator;
4550
4551           if (draw_vgrid_lines)
4552             {
4553               if (list == first_column)
4554                 {
4555                   cell_area.width -= grid_line_width / 2;
4556                 }
4557               else if (list == last_column)
4558                 {
4559                   cell_area.x += grid_line_width / 2;
4560                   cell_area.width -= grid_line_width / 2;
4561                 }
4562               else
4563                 {
4564                   cell_area.x += grid_line_width / 2;
4565                   cell_area.width -= grid_line_width;
4566                 }
4567             }
4568
4569           if (draw_hgrid_lines)
4570             {
4571               cell_area.y += grid_line_width / 2;
4572               cell_area.height -= grid_line_width;
4573             }
4574
4575           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4576             {
4577               cell_offset += column->width;
4578               continue;
4579             }
4580
4581           gtk_tree_view_column_cell_set_cell_data (column,
4582                                                    tree_view->priv->model,
4583                                                    &iter,
4584                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4585                                                    node->children?TRUE:FALSE);
4586
4587           /* Select the detail for drawing the cell.  relevant
4588            * factors are parity, sortedness, and whether to
4589            * display rules.
4590            */
4591           if (allow_rules && tree_view->priv->has_rules)
4592             {
4593               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4594                   n_visible_columns >= 3)
4595                 {
4596                   if (parity)
4597                     detail = "cell_odd_ruled_sorted";
4598                   else
4599                     detail = "cell_even_ruled_sorted";
4600                 }
4601               else
4602                 {
4603                   if (parity)
4604                     detail = "cell_odd_ruled";
4605                   else
4606                     detail = "cell_even_ruled";
4607                 }
4608             }
4609           else
4610             {
4611               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4612                   n_visible_columns >= 3)
4613                 {
4614                   if (parity)
4615                     detail = "cell_odd_sorted";
4616                   else
4617                     detail = "cell_even_sorted";
4618                 }
4619               else
4620                 {
4621                   if (parity)
4622                     detail = "cell_odd";
4623                   else
4624                     detail = "cell_even";
4625                 }
4626             }
4627
4628           g_assert (detail);
4629
4630           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4631             state = GTK_STATE_INSENSITIVE;          
4632           else if (flags & GTK_CELL_RENDERER_SELECTED)
4633             state = GTK_STATE_SELECTED;
4634           else
4635             state = GTK_STATE_NORMAL;
4636
4637           /* Draw background */
4638           is_first = (rtl ? !list->next : !list->prev);
4639           is_last = (rtl ? !list->prev : !list->next);
4640
4641           /* (I don't like the snprintfs either, but couldn't find a
4642            * less messy way).
4643            */
4644           if (is_first && is_last)
4645             g_snprintf (new_detail, 127, "%s", detail);
4646           else if (is_first)
4647             g_snprintf (new_detail, 127, "%s_start", detail);
4648           else if (is_last)
4649             g_snprintf (new_detail, 127, "%s_end", detail);
4650           else
4651             g_snprintf (new_detail, 127, "%s_middle", detail);
4652
4653           gtk_paint_flat_box (style,
4654                               cr,
4655                               state,
4656                               GTK_SHADOW_NONE,
4657                               widget,
4658                               new_detail,
4659                               background_area.x,
4660                               background_area.y,
4661                               background_area.width,
4662                               background_area.height);
4663
4664           if (gtk_tree_view_is_expander_column (tree_view, column))
4665             {
4666               if (!rtl)
4667                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4668               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4669
4670               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4671                 {
4672                   if (!rtl)
4673                     cell_area.x += depth * tree_view->priv->expander_size;
4674                   cell_area.width -= depth * tree_view->priv->expander_size;
4675                 }
4676
4677               /* If we have an expander column, the highlight underline
4678                * starts with that column, so that it indicates which
4679                * level of the tree we're dropping at.
4680                */
4681               highlight_x = cell_area.x;
4682               expander_cell_width = cell_area.width;
4683
4684               if (is_separator)
4685                 gtk_paint_hline (style,
4686                                  cr,
4687                                  state,
4688                                  widget,
4689                                  NULL,
4690                                  cell_area.x,
4691                                  cell_area.x + cell_area.width,
4692                                  cell_area.y + cell_area.height / 2);
4693               else
4694                 _gtk_tree_view_column_cell_render (column,
4695                                                    cr,
4696                                                    &background_area,
4697                                                    &cell_area,
4698                                                    flags);
4699               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4700                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4701                 {
4702                   if (!got_pointer)
4703                     {
4704                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4705                                               &pointer_x, &pointer_y, NULL);
4706                       got_pointer = TRUE;
4707                     }
4708
4709                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4710                                             cr,
4711                                             tree,
4712                                             node,
4713                                             pointer_x, pointer_y);
4714                 }
4715             }
4716           else
4717             {
4718               if (is_separator)
4719                 gtk_paint_hline (style,
4720                                  cr,
4721                                  state,
4722                                  widget,
4723                                  NULL,
4724                                  cell_area.x,
4725                                  cell_area.x + cell_area.width,
4726                                  cell_area.y + cell_area.height / 2);
4727               else
4728                 _gtk_tree_view_column_cell_render (column,
4729                                                    cr,
4730                                                    &background_area,
4731                                                    &cell_area,
4732                                                    flags);
4733             }
4734
4735           if (draw_hgrid_lines)
4736             {
4737               if (background_area.y > 0)
4738                 gtk_tree_view_draw_line (tree_view, cr,
4739                                          GTK_TREE_VIEW_GRID_LINE,
4740                                          background_area.x, background_area.y,
4741                                          background_area.x + background_area.width,
4742                                          background_area.y);
4743
4744               if (y_offset + max_height >= clip.height)
4745                 gtk_tree_view_draw_line (tree_view, cr,
4746                                          GTK_TREE_VIEW_GRID_LINE,
4747                                          background_area.x, background_area.y + max_height,
4748                                          background_area.x + background_area.width,
4749                                          background_area.y + max_height);
4750             }
4751
4752           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4753               tree_view->priv->tree_lines_enabled)
4754             {
4755               gint x = background_area.x;
4756               gint mult = rtl ? -1 : 1;
4757               gint y0 = background_area.y;
4758               gint y1 = background_area.y + background_area.height/2;
4759               gint y2 = background_area.y + background_area.height;
4760
4761               if (rtl)
4762                 x += background_area.width - 1;
4763
4764               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4765                   && depth > 1)
4766                 {
4767                   gtk_tree_view_draw_line (tree_view, cr,
4768                                            GTK_TREE_VIEW_TREE_LINE,
4769                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4770                                            y1,
4771                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4772                                            y1);
4773                 }
4774               else if (depth > 1)
4775                 {
4776                   gtk_tree_view_draw_line (tree_view, cr,
4777                                            GTK_TREE_VIEW_TREE_LINE,
4778                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4779                                            y1,
4780                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4781                                            y1);
4782                 }
4783
4784               if (depth > 1)
4785                 {
4786                   gint i;
4787                   GtkRBNode *tmp_node;
4788                   GtkRBTree *tmp_tree;
4789
4790                   if (!_gtk_rbtree_next (tree, node))
4791                     gtk_tree_view_draw_line (tree_view, cr,
4792                                              GTK_TREE_VIEW_TREE_LINE,
4793                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4794                                              y0,
4795                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4796                                              y1);
4797                   else
4798                     gtk_tree_view_draw_line (tree_view, cr,
4799                                              GTK_TREE_VIEW_TREE_LINE,
4800                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4801                                              y0,
4802                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4803                                              y2);
4804
4805                   tmp_node = tree->parent_node;
4806                   tmp_tree = tree->parent_tree;
4807
4808                   for (i = depth - 2; i > 0; i--)
4809                     {
4810                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4811                         gtk_tree_view_draw_line (tree_view, cr,
4812                                                  GTK_TREE_VIEW_TREE_LINE,
4813                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4814                                                  y0,
4815                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4816                                                  y2);
4817
4818                       tmp_node = tmp_tree->parent_node;
4819                       tmp_tree = tmp_tree->parent_tree;
4820                     }
4821                 }
4822             }
4823
4824           if (node == cursor && has_special_cell &&
4825               ((column == tree_view->priv->focus_column &&
4826                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4827                 gtk_widget_has_focus (widget)) ||
4828                (column == tree_view->priv->edited_column)))
4829             {
4830               _gtk_tree_view_column_cell_draw_focus (column,
4831                                                      cr,
4832                                                      &background_area,
4833                                                      &cell_area,
4834                                                      flags);
4835             }
4836
4837           cell_offset += column->width;
4838         }
4839
4840       if (node == drag_highlight)
4841         {
4842           /* Draw indicator for the drop
4843            */
4844           gint highlight_y = -1;
4845           GtkRBTree *tree = NULL;
4846           GtkRBNode *node = NULL;
4847
4848           switch (tree_view->priv->drag_dest_pos)
4849             {
4850             case GTK_TREE_VIEW_DROP_BEFORE:
4851               highlight_y = background_area.y - 1;
4852               if (highlight_y < 0)
4853                       highlight_y = 0;
4854               break;
4855
4856             case GTK_TREE_VIEW_DROP_AFTER:
4857               highlight_y = background_area.y + background_area.height - 1;
4858               break;
4859
4860             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4861             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4862               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4863
4864               if (tree == NULL)
4865                 break;
4866
4867               gtk_paint_focus (style,
4868                                cr,
4869                                gtk_widget_get_state (widget),
4870                                widget,
4871                                (is_first
4872                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4873                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4874                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4875                                    - focus_line_width / 2,
4876                                 gdk_window_get_width (tree_view->priv->bin_window),
4877                                 ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4878                                    - focus_line_width + 1);
4879               break;
4880             }
4881
4882           if (highlight_y >= 0)
4883             {
4884               gtk_tree_view_draw_line (tree_view, cr,
4885                                        GTK_TREE_VIEW_FOREGROUND_LINE,
4886                                        rtl ? highlight_x + expander_cell_width : highlight_x,
4887                                        highlight_y,
4888                                        rtl ? 0 : bin_window_width,
4889                                        highlight_y);
4890             }
4891         }
4892
4893       /* draw the big row-spanning focus rectangle, if needed */
4894       if (!has_special_cell && node == cursor &&
4895           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4896           gtk_widget_has_focus (widget))
4897         {
4898           gint tmp_y, tmp_height;
4899           GtkStateType focus_rect_state;
4900
4901           focus_rect_state =
4902             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4903             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4904              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4905               GTK_STATE_NORMAL));
4906
4907           if (draw_hgrid_lines)
4908             {
4909               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4910               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4911             }
4912           else
4913             {
4914               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4915               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4916             }
4917
4918           gtk_paint_focus (style,
4919                            cr,
4920                            focus_rect_state,
4921                            widget,
4922                            (is_first
4923                             ? (is_last ? "treeview" : "treeview-left" )
4924                             : (is_last ? "treeview-right" : "treeview-middle" )),
4925                            0, tmp_y,
4926                            gdk_window_get_width (tree_view->priv->bin_window),
4927                            tmp_height);
4928         }
4929
4930       y_offset += max_height;
4931       if (node->children)
4932         {
4933           GtkTreeIter parent = iter;
4934           gboolean has_child;
4935
4936           tree = node->children;
4937           node = tree->root;
4938
4939           g_assert (node != tree->nil);
4940
4941           while (node->left != tree->nil)
4942             node = node->left;
4943           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4944                                                     &iter,
4945                                                     &parent);
4946           depth++;
4947
4948           /* Sanity Check! */
4949           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4950         }
4951       else
4952         {
4953           gboolean done = FALSE;
4954
4955           do
4956             {
4957               node = _gtk_rbtree_next (tree, node);
4958               if (node != NULL)
4959                 {
4960                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4961                   done = TRUE;
4962
4963                   /* Sanity Check! */
4964                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4965                 }
4966               else
4967                 {
4968                   GtkTreeIter parent_iter = iter;
4969                   gboolean has_parent;
4970
4971                   node = tree->parent_node;
4972                   tree = tree->parent_tree;
4973                   if (tree == NULL)
4974                     /* we should go to done to free some memory */
4975                     goto done;
4976                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4977                                                            &iter,
4978                                                            &parent_iter);
4979                   depth--;
4980
4981                   /* Sanity check */
4982                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4983                 }
4984             }
4985           while (!done);
4986         }
4987     }
4988   while (y_offset < clip.height);
4989
4990 done:
4991   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
4992
4993   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4994     gtk_tree_view_paint_rubber_band (tree_view, cr);
4995
4996   if (cursor_path)
4997     gtk_tree_path_free (cursor_path);
4998
4999   if (drag_dest_path)
5000     gtk_tree_path_free (drag_dest_path);
5001
5002   return FALSE;
5003 }
5004
5005 static gboolean
5006 gtk_tree_view_draw (GtkWidget *widget,
5007                     cairo_t   *cr)
5008 {
5009   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5010
5011   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5012     {
5013       GList *tmp_list;
5014
5015       cairo_save (cr);
5016
5017       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5018
5019       gtk_tree_view_bin_draw (widget, cr);
5020
5021       cairo_restore (cr);
5022
5023       /* We can't just chain up to Container::draw as it will try to send the
5024        * event to the headers, so we handle propagating it to our children
5025        * (eg. widgets being edited) ourselves.
5026        */
5027       tmp_list = tree_view->priv->children;
5028       while (tmp_list)
5029         {
5030           GtkTreeViewChild *child = tmp_list->data;
5031           tmp_list = tmp_list->next;
5032
5033           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5034         }
5035     }
5036
5037   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5038     {
5039       GList *list;
5040       
5041       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5042         {
5043           GtkTreeViewColumn *column = list->data;
5044
5045           if (column == tree_view->priv->drag_column)
5046             continue;
5047
5048           if (column->visible)
5049             gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5050                                           column->button,
5051                                           cr);
5052         }
5053     }
5054   
5055   if (tree_view->priv->drag_window &&
5056       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5057     {
5058       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5059                                     tree_view->priv->drag_column->button,
5060                                     cr);
5061     }
5062
5063   return TRUE;
5064 }
5065
5066 enum
5067 {
5068   DROP_HOME,
5069   DROP_RIGHT,
5070   DROP_LEFT,
5071   DROP_END
5072 };
5073
5074 /* returns 0x1 when no column has been found -- yes it's hackish */
5075 static GtkTreeViewColumn *
5076 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5077                                GtkTreeViewColumn *column,
5078                                gint               drop_position)
5079 {
5080   GtkTreeViewColumn *left_column = NULL;
5081   GtkTreeViewColumn *cur_column = NULL;
5082   GList *tmp_list;
5083
5084   if (!column->reorderable)
5085     return (GtkTreeViewColumn *)0x1;
5086
5087   switch (drop_position)
5088     {
5089       case DROP_HOME:
5090         /* find first column where we can drop */
5091         tmp_list = tree_view->priv->columns;
5092         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5093           return (GtkTreeViewColumn *)0x1;
5094
5095         while (tmp_list)
5096           {
5097             g_assert (tmp_list);
5098
5099             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5100             tmp_list = tmp_list->next;
5101
5102             if (left_column && left_column->visible == FALSE)
5103               continue;
5104
5105             if (!tree_view->priv->column_drop_func)
5106               return left_column;
5107
5108             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5109               {
5110                 left_column = cur_column;
5111                 continue;
5112               }
5113
5114             return left_column;
5115           }
5116
5117         if (!tree_view->priv->column_drop_func)
5118           return left_column;
5119
5120         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5121           return left_column;
5122         else
5123           return (GtkTreeViewColumn *)0x1;
5124         break;
5125
5126       case DROP_RIGHT:
5127         /* find first column after column where we can drop */
5128         tmp_list = tree_view->priv->columns;
5129
5130         for (; tmp_list; tmp_list = tmp_list->next)
5131           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5132             break;
5133
5134         if (!tmp_list || !tmp_list->next)
5135           return (GtkTreeViewColumn *)0x1;
5136
5137         tmp_list = tmp_list->next;
5138         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5139         tmp_list = tmp_list->next;
5140
5141         while (tmp_list)
5142           {
5143             g_assert (tmp_list);
5144
5145             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5146             tmp_list = tmp_list->next;
5147
5148             if (left_column && left_column->visible == FALSE)
5149               {
5150                 left_column = cur_column;
5151                 if (tmp_list)
5152                   tmp_list = tmp_list->next;
5153                 continue;
5154               }
5155
5156             if (!tree_view->priv->column_drop_func)
5157               return left_column;
5158
5159             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5160               {
5161                 left_column = cur_column;
5162                 continue;
5163               }
5164
5165             return left_column;
5166           }
5167
5168         if (!tree_view->priv->column_drop_func)
5169           return left_column;
5170
5171         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5172           return left_column;
5173         else
5174           return (GtkTreeViewColumn *)0x1;
5175         break;
5176
5177       case DROP_LEFT:
5178         /* find first column before column where we can drop */
5179         tmp_list = tree_view->priv->columns;
5180
5181         for (; tmp_list; tmp_list = tmp_list->next)
5182           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5183             break;
5184
5185         if (!tmp_list || !tmp_list->prev)
5186           return (GtkTreeViewColumn *)0x1;
5187
5188         tmp_list = tmp_list->prev;
5189         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5190         tmp_list = tmp_list->prev;
5191
5192         while (tmp_list)
5193           {
5194             g_assert (tmp_list);
5195
5196             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5197
5198             if (left_column && !left_column->visible)
5199               {
5200                 /*if (!tmp_list->prev)
5201                   return (GtkTreeViewColumn *)0x1;
5202                   */
5203 /*
5204                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5205                 tmp_list = tmp_list->prev->prev;
5206                 continue;*/
5207
5208                 cur_column = left_column;
5209                 if (tmp_list)
5210                   tmp_list = tmp_list->prev;
5211                 continue;
5212               }
5213
5214             if (!tree_view->priv->column_drop_func)
5215               return left_column;
5216
5217             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5218               return left_column;
5219
5220             cur_column = left_column;
5221             tmp_list = tmp_list->prev;
5222           }
5223
5224         if (!tree_view->priv->column_drop_func)
5225           return NULL;
5226
5227         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5228           return NULL;
5229         else
5230           return (GtkTreeViewColumn *)0x1;
5231         break;
5232
5233       case DROP_END:
5234         /* same as DROP_HOME case, but doing it backwards */
5235         tmp_list = g_list_last (tree_view->priv->columns);
5236         cur_column = NULL;
5237
5238         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5239           return (GtkTreeViewColumn *)0x1;
5240
5241         while (tmp_list)
5242           {
5243             g_assert (tmp_list);
5244
5245             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5246
5247             if (left_column && !left_column->visible)
5248               {
5249                 cur_column = left_column;
5250                 tmp_list = tmp_list->prev;
5251               }
5252
5253             if (!tree_view->priv->column_drop_func)
5254               return left_column;
5255
5256             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5257               return left_column;
5258
5259             cur_column = left_column;
5260             tmp_list = tmp_list->prev;
5261           }
5262
5263         if (!tree_view->priv->column_drop_func)
5264           return NULL;
5265
5266         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5267           return NULL;
5268         else
5269           return (GtkTreeViewColumn *)0x1;
5270         break;
5271     }
5272
5273   return (GtkTreeViewColumn *)0x1;
5274 }
5275
5276 static gboolean
5277 gtk_tree_view_key_press (GtkWidget   *widget,
5278                          GdkEventKey *event)
5279 {
5280   GtkTreeView *tree_view = (GtkTreeView *) widget;
5281
5282   if (tree_view->priv->rubber_band_status)
5283     {
5284       if (event->keyval == GDK_KEY_Escape)
5285         gtk_tree_view_stop_rubber_band (tree_view);
5286
5287       return TRUE;
5288     }
5289
5290   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5291     {
5292       if (event->keyval == GDK_KEY_Escape)
5293         {
5294           tree_view->priv->cur_reorder = NULL;
5295           gtk_tree_view_button_release_drag_column (widget, NULL);
5296         }
5297       return TRUE;
5298     }
5299
5300   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5301     {
5302       GList *focus_column;
5303       gboolean rtl;
5304
5305       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5306
5307       for (focus_column = tree_view->priv->columns;
5308            focus_column;
5309            focus_column = focus_column->next)
5310         {
5311           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5312
5313           if (gtk_widget_has_focus (column->button))
5314             break;
5315         }
5316
5317       if (focus_column &&
5318           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5319           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5320            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5321         {
5322           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5323
5324           if (!column->resizable)
5325             {
5326               gtk_widget_error_bell (widget);
5327               return TRUE;
5328             }
5329
5330           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5331               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5332             {
5333               GtkRequisition button_req;
5334               gint old_width = column->resized_width;
5335
5336               gtk_widget_get_preferred_size (column->button, &button_req, NULL);
5337
5338               column->resized_width = MAX (column->resized_width,
5339                                            column->width);
5340               column->resized_width -= 2;
5341               if (column->resized_width < 0)
5342                 column->resized_width = 0;
5343
5344               if (column->min_width == -1)
5345                 column->resized_width = MAX (button_req.width,
5346                                              column->resized_width);
5347               else
5348                 {
5349                   column->resized_width = MAX (column->min_width,
5350                                                column->resized_width);
5351                 }
5352
5353               if (column->max_width != -1)
5354                 column->resized_width = MIN (column->resized_width,
5355                                              column->max_width);
5356
5357               column->use_resized_width = TRUE;
5358
5359               if (column->resized_width != old_width)
5360                 gtk_widget_queue_resize (widget);
5361               else
5362                 gtk_widget_error_bell (widget);
5363             }
5364           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5365                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5366             {
5367               gint old_width = column->resized_width;
5368
5369               column->resized_width = MAX (column->resized_width,
5370                                            column->width);
5371               column->resized_width += 2;
5372
5373               if (column->max_width != -1)
5374                 column->resized_width = MIN (column->resized_width,
5375                                              column->max_width);
5376
5377               column->use_resized_width = TRUE;
5378
5379               if (column->resized_width != old_width)
5380                 gtk_widget_queue_resize (widget);
5381               else
5382                 gtk_widget_error_bell (widget);
5383             }
5384
5385           return TRUE;
5386         }
5387
5388       if (focus_column &&
5389           (event->state & GDK_MOD1_MASK) &&
5390           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5391            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5392            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5393            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5394         {
5395           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5396
5397           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5398               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5399             {
5400               GtkTreeViewColumn *col;
5401               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5402               if (col != (GtkTreeViewColumn *)0x1)
5403                 gtk_tree_view_move_column_after (tree_view, column, col);
5404               else
5405                 gtk_widget_error_bell (widget);
5406             }
5407           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5408                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5409             {
5410               GtkTreeViewColumn *col;
5411               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5412               if (col != (GtkTreeViewColumn *)0x1)
5413                 gtk_tree_view_move_column_after (tree_view, column, col);
5414               else
5415                 gtk_widget_error_bell (widget);
5416             }
5417           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5418             {
5419               GtkTreeViewColumn *col;
5420               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5421               if (col != (GtkTreeViewColumn *)0x1)
5422                 gtk_tree_view_move_column_after (tree_view, column, col);
5423               else
5424                 gtk_widget_error_bell (widget);
5425             }
5426           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5427             {
5428               GtkTreeViewColumn *col;
5429               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5430               if (col != (GtkTreeViewColumn *)0x1)
5431                 gtk_tree_view_move_column_after (tree_view, column, col);
5432               else
5433                 gtk_widget_error_bell (widget);
5434             }
5435
5436           return TRUE;
5437         }
5438     }
5439
5440   /* Chain up to the parent class.  It handles the keybindings. */
5441   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5442     return TRUE;
5443
5444   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5445     {
5446       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5447       return FALSE;
5448     }
5449
5450   /* We pass the event to the search_entry.  If its text changes, then we start
5451    * the typeahead find capabilities. */
5452   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5453       && tree_view->priv->enable_search
5454       && !tree_view->priv->search_custom_entry_set)
5455     {
5456       GdkEvent *new_event;
5457       char *old_text;
5458       const char *new_text;
5459       gboolean retval;
5460       GdkScreen *screen;
5461       gboolean text_modified;
5462       gulong popup_menu_id;
5463
5464       gtk_tree_view_ensure_interactive_directory (tree_view);
5465
5466       /* Make a copy of the current text */
5467       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5468       new_event = gdk_event_copy ((GdkEvent *) event);
5469       g_object_unref (((GdkEventKey *) new_event)->window);
5470       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5471       gtk_widget_realize (tree_view->priv->search_window);
5472
5473       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5474                                         "popup-menu", G_CALLBACK (gtk_true),
5475                                         NULL);
5476
5477       /* Move the entry off screen */
5478       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5479       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5480                        gdk_screen_get_width (screen) + 1,
5481                        gdk_screen_get_height (screen) + 1);
5482       gtk_widget_show (tree_view->priv->search_window);
5483
5484       /* Send the event to the window.  If the preedit_changed signal is emitted
5485        * during this event, we will set priv->imcontext_changed  */
5486       tree_view->priv->imcontext_changed = FALSE;
5487       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5488       gdk_event_free (new_event);
5489       gtk_widget_hide (tree_view->priv->search_window);
5490
5491       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5492                                    popup_menu_id);
5493
5494       /* We check to make sure that the entry tried to handle the text, and that
5495        * the text has changed.
5496        */
5497       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5498       text_modified = strcmp (old_text, new_text) != 0;
5499       g_free (old_text);
5500       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5501           (retval && text_modified))               /* ...or the text was modified */
5502         {
5503           if (gtk_tree_view_real_start_interactive_search (tree_view,
5504                                                            gdk_event_get_device ((GdkEvent *) event),
5505                                                            FALSE))
5506             {
5507               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5508               return TRUE;
5509             }
5510           else
5511             {
5512               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5513               return FALSE;
5514             }
5515         }
5516     }
5517
5518   return FALSE;
5519 }
5520
5521 static gboolean
5522 gtk_tree_view_key_release (GtkWidget   *widget,
5523                            GdkEventKey *event)
5524 {
5525   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5526
5527   if (tree_view->priv->rubber_band_status)
5528     return TRUE;
5529
5530   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5531 }
5532
5533 /* FIXME Is this function necessary? Can I get an enter_notify event
5534  * w/o either an expose event or a mouse motion event?
5535  */
5536 static gboolean
5537 gtk_tree_view_enter_notify (GtkWidget        *widget,
5538                             GdkEventCrossing *event)
5539 {
5540   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5541   GtkRBTree *tree;
5542   GtkRBNode *node;
5543   gint new_y;
5544
5545   /* Sanity check it */
5546   if (event->window != tree_view->priv->bin_window)
5547     return FALSE;
5548
5549   if (tree_view->priv->tree == NULL)
5550     return FALSE;
5551
5552   if (event->mode == GDK_CROSSING_GRAB ||
5553       event->mode == GDK_CROSSING_GTK_GRAB ||
5554       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5555       event->mode == GDK_CROSSING_STATE_CHANGED)
5556     return TRUE;
5557
5558   /* find the node internally */
5559   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5560   if (new_y < 0)
5561     new_y = 0;
5562   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5563
5564   tree_view->priv->event_last_x = event->x;
5565   tree_view->priv->event_last_y = event->y;
5566
5567   if ((tree_view->priv->button_pressed_node == NULL) ||
5568       (tree_view->priv->button_pressed_node == node))
5569     prelight_or_select (tree_view, tree, node, event->x, event->y);
5570
5571   return TRUE;
5572 }
5573
5574 static gboolean
5575 gtk_tree_view_leave_notify (GtkWidget        *widget,
5576                             GdkEventCrossing *event)
5577 {
5578   GtkTreeView *tree_view;
5579
5580   if (event->mode == GDK_CROSSING_GRAB)
5581     return TRUE;
5582
5583   tree_view = GTK_TREE_VIEW (widget);
5584
5585   if (tree_view->priv->prelight_node)
5586     _gtk_tree_view_queue_draw_node (tree_view,
5587                                    tree_view->priv->prelight_tree,
5588                                    tree_view->priv->prelight_node,
5589                                    NULL);
5590
5591   tree_view->priv->event_last_x = -10000;
5592   tree_view->priv->event_last_y = -10000;
5593
5594   prelight_or_select (tree_view,
5595                       NULL, NULL,
5596                       -1000, -1000); /* coords not possibly over an arrow */
5597
5598   return TRUE;
5599 }
5600
5601
5602 static gint
5603 gtk_tree_view_focus_out (GtkWidget     *widget,
5604                          GdkEventFocus *event)
5605 {
5606   GtkTreeView *tree_view;
5607
5608   tree_view = GTK_TREE_VIEW (widget);
5609
5610   gtk_widget_queue_draw (widget);
5611
5612   /* destroy interactive search dialog */
5613   if (tree_view->priv->search_window)
5614     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5615                                       gdk_event_get_device ((GdkEvent *) event));
5616
5617   return FALSE;
5618 }
5619
5620
5621 /* Incremental Reflow
5622  */
5623
5624 static void
5625 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5626                                  GtkRBTree   *tree,
5627                                  GtkRBNode   *node)
5628 {
5629   GtkAllocation allocation;
5630   gint y;
5631
5632   y = _gtk_rbtree_node_find_offset (tree, node)
5633     - tree_view->priv->vadjustment->value
5634     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5635
5636   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5637   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5638                               0, y,
5639                               allocation.width,
5640                               GTK_RBNODE_GET_HEIGHT (node));
5641 }
5642
5643 static gboolean
5644 node_is_visible (GtkTreeView *tree_view,
5645                  GtkRBTree   *tree,
5646                  GtkRBNode   *node)
5647 {
5648   int y;
5649   int height;
5650
5651   y = _gtk_rbtree_node_find_offset (tree, node);
5652   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5653
5654   if (y >= tree_view->priv->vadjustment->value &&
5655       y + height <= (tree_view->priv->vadjustment->value
5656                      + tree_view->priv->vadjustment->page_size))
5657     return TRUE;
5658
5659   return FALSE;
5660 }
5661
5662 /* Returns TRUE if it updated the size
5663  */
5664 static gboolean
5665 validate_row (GtkTreeView *tree_view,
5666               GtkRBTree   *tree,
5667               GtkRBNode   *node,
5668               GtkTreeIter *iter,
5669               GtkTreePath *path)
5670 {
5671   GtkTreeViewColumn *column;
5672   GList *list, *first_column, *last_column;
5673   gint height = 0;
5674   gint horizontal_separator;
5675   gint vertical_separator;
5676   gint focus_line_width;
5677   gint depth = gtk_tree_path_get_depth (path);
5678   gboolean retval = FALSE;
5679   gboolean is_separator = FALSE;
5680   gboolean draw_vgrid_lines, draw_hgrid_lines;
5681   gint focus_pad;
5682   gint grid_line_width;
5683   gboolean wide_separators;
5684   gint separator_height;
5685
5686   /* double check the row needs validating */
5687   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5688       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5689     return FALSE;
5690
5691   is_separator = row_is_separator (tree_view, iter, NULL);
5692
5693   gtk_widget_style_get (GTK_WIDGET (tree_view),
5694                         "focus-padding", &focus_pad,
5695                         "focus-line-width", &focus_line_width,
5696                         "horizontal-separator", &horizontal_separator,
5697                         "vertical-separator", &vertical_separator,
5698                         "grid-line-width", &grid_line_width,
5699                         "wide-separators",  &wide_separators,
5700                         "separator-height", &separator_height,
5701                         NULL);
5702   
5703   draw_vgrid_lines =
5704     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5705     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5706   draw_hgrid_lines =
5707     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5708     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5709
5710   for (last_column = g_list_last (tree_view->priv->columns);
5711        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5712        last_column = last_column->prev)
5713     ;
5714
5715   for (first_column = g_list_first (tree_view->priv->columns);
5716        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5717        first_column = first_column->next)
5718     ;
5719
5720   for (list = tree_view->priv->columns; list; list = list->next)
5721     {
5722       gint tmp_width;
5723       gint tmp_height;
5724
5725       column = list->data;
5726
5727       if (! column->visible)
5728         continue;
5729
5730       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5731         continue;
5732
5733       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5734                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5735                                                node->children?TRUE:FALSE);
5736       gtk_tree_view_column_cell_get_size (column,
5737                                           NULL, NULL, NULL,
5738                                           &tmp_width, &tmp_height);
5739
5740       if (!is_separator)
5741         {
5742           tmp_height += vertical_separator;
5743           height = MAX (height, tmp_height);
5744           height = MAX (height, tree_view->priv->expander_size);
5745         }
5746       else
5747         {
5748           if (wide_separators)
5749             height = separator_height + 2 * focus_pad;
5750           else
5751             height = 2 + 2 * focus_pad;
5752         }
5753
5754       if (gtk_tree_view_is_expander_column (tree_view, column))
5755         {
5756           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5757
5758           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5759             tmp_width += depth * tree_view->priv->expander_size;
5760         }
5761       else
5762         tmp_width = tmp_width + horizontal_separator;
5763
5764       if (draw_vgrid_lines)
5765         {
5766           if (list->data == first_column || list->data == last_column)
5767             tmp_width += grid_line_width / 2.0;
5768           else
5769             tmp_width += grid_line_width;
5770         }
5771
5772       if (tmp_width > column->requested_width)
5773         {
5774           retval = TRUE;
5775           column->requested_width = tmp_width;
5776         }
5777     }
5778
5779   if (draw_hgrid_lines)
5780     height += grid_line_width;
5781
5782   if (height != GTK_RBNODE_GET_HEIGHT (node))
5783     {
5784       retval = TRUE;
5785       _gtk_rbtree_node_set_height (tree, node, height);
5786     }
5787   _gtk_rbtree_node_mark_valid (tree, node);
5788   tree_view->priv->post_validation_flag = TRUE;
5789
5790   return retval;
5791 }
5792
5793
5794 static void
5795 validate_visible_area (GtkTreeView *tree_view)
5796 {
5797   GtkAllocation allocation;
5798   GtkTreePath *path = NULL;
5799   GtkTreePath *above_path = NULL;
5800   GtkTreeIter iter;
5801   GtkRBTree *tree = NULL;
5802   GtkRBNode *node = NULL;
5803   gboolean need_redraw = FALSE;
5804   gboolean size_changed = FALSE;
5805   gint total_height;
5806   gint area_above = 0;
5807   gint area_below = 0;
5808
5809   if (tree_view->priv->tree == NULL)
5810     return;
5811
5812   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5813       tree_view->priv->scroll_to_path == NULL)
5814     return;
5815
5816   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5817   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5818
5819   if (total_height == 0)
5820     return;
5821
5822   /* First, we check to see if we need to scroll anywhere
5823    */
5824   if (tree_view->priv->scroll_to_path)
5825     {
5826       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5827       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5828         {
5829           /* we are going to scroll, and will update dy */
5830           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5831           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5832               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5833             {
5834               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5835               if (validate_row (tree_view, tree, node, &iter, path))
5836                 size_changed = TRUE;
5837             }
5838
5839           if (tree_view->priv->scroll_to_use_align)
5840             {
5841               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5842               area_above = (total_height - height) *
5843                 tree_view->priv->scroll_to_row_align;
5844               area_below = total_height - area_above - height;
5845               area_above = MAX (area_above, 0);
5846               area_below = MAX (area_below, 0);
5847             }
5848           else
5849             {
5850               /* two cases:
5851                * 1) row not visible
5852                * 2) row visible
5853                */
5854               gint dy;
5855               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5856
5857               dy = _gtk_rbtree_node_find_offset (tree, node);
5858
5859               if (dy >= tree_view->priv->vadjustment->value &&
5860                   dy + height <= (tree_view->priv->vadjustment->value
5861                                   + tree_view->priv->vadjustment->page_size))
5862                 {
5863                   /* row visible: keep the row at the same position */
5864                   area_above = dy - tree_view->priv->vadjustment->value;
5865                   area_below = (tree_view->priv->vadjustment->value +
5866                                 tree_view->priv->vadjustment->page_size)
5867                                - dy - height;
5868                 }
5869               else
5870                 {
5871                   /* row not visible */
5872                   if (dy >= 0
5873                       && dy + height <= tree_view->priv->vadjustment->page_size)
5874                     {
5875                       /* row at the beginning -- fixed */
5876                       area_above = dy;
5877                       area_below = tree_view->priv->vadjustment->page_size
5878                                    - area_above - height;
5879                     }
5880                   else if (dy >= (tree_view->priv->vadjustment->upper -
5881                                   tree_view->priv->vadjustment->page_size))
5882                     {
5883                       /* row at the end -- fixed */
5884                       area_above = dy - (tree_view->priv->vadjustment->upper -
5885                                    tree_view->priv->vadjustment->page_size);
5886                       area_below = tree_view->priv->vadjustment->page_size -
5887                                    area_above - height;
5888
5889                       if (area_below < 0)
5890                         {
5891                           area_above = tree_view->priv->vadjustment->page_size - height;
5892                           area_below = 0;
5893                         }
5894                     }
5895                   else
5896                     {
5897                       /* row somewhere in the middle, bring it to the top
5898                        * of the view
5899                        */
5900                       area_above = 0;
5901                       area_below = total_height - height;
5902                     }
5903                 }
5904             }
5905         }
5906       else
5907         /* the scroll to isn't valid; ignore it.
5908          */
5909         {
5910           if (tree_view->priv->scroll_to_path && !path)
5911             {
5912               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5913               tree_view->priv->scroll_to_path = NULL;
5914             }
5915           if (path)
5916             gtk_tree_path_free (path);
5917           path = NULL;
5918         }      
5919     }
5920
5921   /* We didn't have a scroll_to set, so we just handle things normally
5922    */
5923   if (path == NULL)
5924     {
5925       gint offset;
5926
5927       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5928                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5929                                         &tree, &node);
5930       if (node == NULL)
5931         {
5932           /* In this case, nothing has been validated */
5933           path = gtk_tree_path_new_first ();
5934           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5935         }
5936       else
5937         {
5938           path = _gtk_tree_view_find_path (tree_view, tree, node);
5939           total_height += offset;
5940         }
5941
5942       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5943
5944       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5945           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5946         {
5947           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5948           if (validate_row (tree_view, tree, node, &iter, path))
5949             size_changed = TRUE;
5950         }
5951       area_above = 0;
5952       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5953     }
5954
5955   above_path = gtk_tree_path_copy (path);
5956
5957   /* if we do not validate any row above the new top_row, we will make sure
5958    * that the row immediately above top_row has been validated. (if we do not
5959    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5960    * when invalidated that row's height will be zero. and this will mess up
5961    * scrolling).
5962    */
5963   if (area_above == 0)
5964     {
5965       GtkRBTree *tmptree;
5966       GtkRBNode *tmpnode;
5967
5968       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5969       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5970
5971       if (tmpnode)
5972         {
5973           GtkTreePath *tmppath;
5974           GtkTreeIter tmpiter;
5975
5976           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5977           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5978
5979           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5980               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5981             {
5982               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5983               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5984                 size_changed = TRUE;
5985             }
5986
5987           gtk_tree_path_free (tmppath);
5988         }
5989     }
5990
5991   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5992    * backwards is much slower then forward, as there is no iter_prev function.
5993    * We go forwards first in case we run out of tree.  Then we go backwards to
5994    * fill out the top.
5995    */
5996   while (node && area_below > 0)
5997     {
5998       if (node->children)
5999         {
6000           GtkTreeIter parent = iter;
6001           gboolean has_child;
6002
6003           tree = node->children;
6004           node = tree->root;
6005
6006           g_assert (node != tree->nil);
6007
6008           while (node->left != tree->nil)
6009             node = node->left;
6010           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6011                                                     &iter,
6012                                                     &parent);
6013           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6014           gtk_tree_path_down (path);
6015         }
6016       else
6017         {
6018           gboolean done = FALSE;
6019           do
6020             {
6021               node = _gtk_rbtree_next (tree, node);
6022               if (node != NULL)
6023                 {
6024                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6025                   done = TRUE;
6026                   gtk_tree_path_next (path);
6027
6028                   /* Sanity Check! */
6029                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6030                 }
6031               else
6032                 {
6033                   GtkTreeIter parent_iter = iter;
6034                   gboolean has_parent;
6035
6036                   node = tree->parent_node;
6037                   tree = tree->parent_tree;
6038                   if (tree == NULL)
6039                     break;
6040                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6041                                                            &iter,
6042                                                            &parent_iter);
6043                   gtk_tree_path_up (path);
6044
6045                   /* Sanity check */
6046                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6047                 }
6048             }
6049           while (!done);
6050         }
6051
6052       if (!node)
6053         break;
6054
6055       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6056           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6057         {
6058           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6059           if (validate_row (tree_view, tree, node, &iter, path))
6060               size_changed = TRUE;
6061         }
6062
6063       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6064     }
6065   gtk_tree_path_free (path);
6066
6067   /* If we ran out of tree, and have extra area_below left, we need to add it
6068    * to area_above */
6069   if (area_below > 0)
6070     area_above += area_below;
6071
6072   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6073
6074   /* We walk backwards */
6075   while (area_above > 0)
6076     {
6077       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6078
6079       /* Always find the new path in the tree.  We cannot just assume
6080        * a gtk_tree_path_prev() is enough here, as there might be children
6081        * in between this node and the previous sibling node.  If this
6082        * appears to be a performance hotspot in profiles, we can look into
6083        * intrigate logic for keeping path, node and iter in sync like
6084        * we do for forward walks.  (Which will be hard because of the lacking
6085        * iter_prev).
6086        */
6087
6088       if (node == NULL)
6089         break;
6090
6091       gtk_tree_path_free (above_path);
6092       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6093
6094       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6095
6096       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6097           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6098         {
6099           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6100           if (validate_row (tree_view, tree, node, &iter, above_path))
6101             size_changed = TRUE;
6102         }
6103       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6104     }
6105
6106   /* if we scrolled to a path, we need to set the dy here,
6107    * and sync the top row accordingly
6108    */
6109   if (tree_view->priv->scroll_to_path)
6110     {
6111       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6112       gtk_tree_view_top_row_to_dy (tree_view);
6113
6114       need_redraw = TRUE;
6115     }
6116   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6117     {
6118       /* when we are not scrolling, we should never set dy to something
6119        * else than zero. we update top_row to be in sync with dy = 0.
6120        */
6121       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6122       gtk_tree_view_dy_to_top_row (tree_view);
6123     }
6124   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6125     {
6126       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6127       gtk_tree_view_dy_to_top_row (tree_view);
6128     }
6129   else
6130     gtk_tree_view_top_row_to_dy (tree_view);
6131
6132   /* update width/height and queue a resize */
6133   if (size_changed)
6134     {
6135       GtkRequisition requisition;
6136
6137       /* We temporarily guess a size, under the assumption that it will be the
6138        * same when we get our next size_allocate.  If we don't do this, we'll be
6139        * in an inconsistent state if we call top_row_to_dy. */
6140
6141       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6142                                      &requisition, NULL);
6143       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6144       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6145       gtk_adjustment_changed (tree_view->priv->hadjustment);
6146       gtk_adjustment_changed (tree_view->priv->vadjustment);
6147       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6148     }
6149
6150   if (tree_view->priv->scroll_to_path)
6151     {
6152       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6153       tree_view->priv->scroll_to_path = NULL;
6154     }
6155
6156   if (above_path)
6157     gtk_tree_path_free (above_path);
6158
6159   if (tree_view->priv->scroll_to_column)
6160     {
6161       tree_view->priv->scroll_to_column = NULL;
6162     }
6163   if (need_redraw)
6164     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6165 }
6166
6167 static void
6168 initialize_fixed_height_mode (GtkTreeView *tree_view)
6169 {
6170   if (!tree_view->priv->tree)
6171     return;
6172
6173   if (tree_view->priv->fixed_height < 0)
6174     {
6175       GtkTreeIter iter;
6176       GtkTreePath *path;
6177
6178       GtkRBTree *tree = NULL;
6179       GtkRBNode *node = NULL;
6180
6181       tree = tree_view->priv->tree;
6182       node = tree->root;
6183
6184       path = _gtk_tree_view_find_path (tree_view, tree, node);
6185       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6186
6187       validate_row (tree_view, tree, node, &iter, path);
6188
6189       gtk_tree_path_free (path);
6190
6191       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6192     }
6193
6194    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6195                                  tree_view->priv->fixed_height, TRUE);
6196 }
6197
6198 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6199  * the left-most uninvalidated node.  We then try walking right, validating
6200  * nodes.  Once we find a valid node, we repeat the previous process of finding
6201  * the first invalid node.
6202  */
6203
6204 static gboolean
6205 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6206 {
6207   GtkRBTree *tree = NULL;
6208   GtkRBNode *node = NULL;
6209   gboolean validated_area = FALSE;
6210   gint retval = TRUE;
6211   GtkTreePath *path = NULL;
6212   GtkTreeIter iter;
6213   GTimer *timer;
6214   gint i = 0;
6215
6216   gint prev_height = -1;
6217   gboolean fixed_height = TRUE;
6218
6219   g_assert (tree_view);
6220
6221   if (tree_view->priv->tree == NULL)
6222       return FALSE;
6223
6224   if (tree_view->priv->fixed_height_mode)
6225     {
6226       if (tree_view->priv->fixed_height < 0)
6227         initialize_fixed_height_mode (tree_view);
6228
6229       return FALSE;
6230     }
6231
6232   timer = g_timer_new ();
6233   g_timer_start (timer);
6234
6235   do
6236     {
6237       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6238         {
6239           retval = FALSE;
6240           goto done;
6241         }
6242
6243       if (path != NULL)
6244         {
6245           node = _gtk_rbtree_next (tree, node);
6246           if (node != NULL)
6247             {
6248               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6249               gtk_tree_path_next (path);
6250             }
6251           else
6252             {
6253               gtk_tree_path_free (path);
6254               path = NULL;
6255             }
6256         }
6257
6258       if (path == NULL)
6259         {
6260           tree = tree_view->priv->tree;
6261           node = tree_view->priv->tree->root;
6262
6263           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6264
6265           do
6266             {
6267               if (node->left != tree->nil &&
6268                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6269                 {
6270                   node = node->left;
6271                 }
6272               else if (node->right != tree->nil &&
6273                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6274                 {
6275                   node = node->right;
6276                 }
6277               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6278                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6279                 {
6280                   break;
6281                 }
6282               else if (node->children != NULL)
6283                 {
6284                   tree = node->children;
6285                   node = tree->root;
6286                 }
6287               else
6288                 /* RBTree corruption!  All bad */
6289                 g_assert_not_reached ();
6290             }
6291           while (TRUE);
6292           path = _gtk_tree_view_find_path (tree_view, tree, node);
6293           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6294         }
6295
6296       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6297                        validated_area;
6298
6299       if (!tree_view->priv->fixed_height_check)
6300         {
6301           gint height;
6302
6303           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6304           if (prev_height < 0)
6305             prev_height = height;
6306           else if (prev_height != height)
6307             fixed_height = FALSE;
6308         }
6309
6310       i++;
6311     }
6312   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6313
6314   if (!tree_view->priv->fixed_height_check)
6315    {
6316      if (fixed_height)
6317        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6318
6319      tree_view->priv->fixed_height_check = 1;
6320    }
6321   
6322  done:
6323   if (validated_area)
6324     {
6325       GtkRequisition requisition;
6326       /* We temporarily guess a size, under the assumption that it will be the
6327        * same when we get our next size_allocate.  If we don't do this, we'll be
6328        * in an inconsistent state when we call top_row_to_dy. */
6329
6330       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6331                                      &requisition, NULL);
6332       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6333       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6334       gtk_adjustment_changed (tree_view->priv->hadjustment);
6335       gtk_adjustment_changed (tree_view->priv->vadjustment);
6336
6337       if (queue_resize)
6338         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6339     }
6340
6341   if (path) gtk_tree_path_free (path);
6342   g_timer_destroy (timer);
6343
6344   return retval;
6345 }
6346
6347 static gboolean
6348 validate_rows (GtkTreeView *tree_view)
6349 {
6350   gboolean retval;
6351   
6352   retval = do_validate_rows (tree_view, TRUE);
6353   
6354   if (! retval && tree_view->priv->validate_rows_timer)
6355     {
6356       g_source_remove (tree_view->priv->validate_rows_timer);
6357       tree_view->priv->validate_rows_timer = 0;
6358     }
6359
6360   return retval;
6361 }
6362
6363 static gboolean
6364 validate_rows_handler (GtkTreeView *tree_view)
6365 {
6366   gboolean retval;
6367
6368   retval = do_validate_rows (tree_view, TRUE);
6369   if (! retval && tree_view->priv->validate_rows_timer)
6370     {
6371       g_source_remove (tree_view->priv->validate_rows_timer);
6372       tree_view->priv->validate_rows_timer = 0;
6373     }
6374
6375   return retval;
6376 }
6377
6378 static gboolean
6379 do_presize_handler (GtkTreeView *tree_view)
6380 {
6381   if (tree_view->priv->mark_rows_col_dirty)
6382     {
6383       if (tree_view->priv->tree)
6384         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6385       tree_view->priv->mark_rows_col_dirty = FALSE;
6386     }
6387   validate_visible_area (tree_view);
6388   tree_view->priv->presize_handler_timer = 0;
6389
6390   if (tree_view->priv->fixed_height_mode)
6391     {
6392       GtkRequisition requisition;
6393
6394       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6395                                      &requisition, NULL);
6396
6397       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6398       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6399       gtk_adjustment_changed (tree_view->priv->hadjustment);
6400       gtk_adjustment_changed (tree_view->priv->vadjustment);
6401       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6402     }
6403                    
6404   return FALSE;
6405 }
6406
6407 static gboolean
6408 presize_handler_callback (gpointer data)
6409 {
6410   do_presize_handler (GTK_TREE_VIEW (data));
6411                    
6412   return FALSE;
6413 }
6414
6415 static void
6416 install_presize_handler (GtkTreeView *tree_view)
6417 {
6418   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6419     return;
6420
6421   if (! tree_view->priv->presize_handler_timer)
6422     {
6423       tree_view->priv->presize_handler_timer =
6424         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6425     }
6426   if (! tree_view->priv->validate_rows_timer)
6427     {
6428       tree_view->priv->validate_rows_timer =
6429         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6430     }
6431 }
6432
6433 static gboolean
6434 scroll_sync_handler (GtkTreeView *tree_view)
6435 {
6436   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6437     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6438   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6439     gtk_tree_view_top_row_to_dy (tree_view);
6440   else
6441     gtk_tree_view_dy_to_top_row (tree_view);
6442
6443   tree_view->priv->scroll_sync_timer = 0;
6444
6445   return FALSE;
6446 }
6447
6448 static void
6449 install_scroll_sync_handler (GtkTreeView *tree_view)
6450 {
6451   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6452     return;
6453
6454   if (!tree_view->priv->scroll_sync_timer)
6455     {
6456       tree_view->priv->scroll_sync_timer =
6457         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6458     }
6459 }
6460
6461 static void
6462 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6463                            GtkTreePath *path,
6464                            gint         offset)
6465 {
6466   gtk_tree_row_reference_free (tree_view->priv->top_row);
6467
6468   if (!path)
6469     {
6470       tree_view->priv->top_row = NULL;
6471       tree_view->priv->top_row_dy = 0;
6472     }
6473   else
6474     {
6475       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6476       tree_view->priv->top_row_dy = offset;
6477     }
6478 }
6479
6480 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6481  * it's set to be NULL, and top_row_dy is 0;
6482  */
6483 static void
6484 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6485 {
6486   gint offset;
6487   GtkTreePath *path;
6488   GtkRBTree *tree;
6489   GtkRBNode *node;
6490
6491   if (tree_view->priv->tree == NULL)
6492     {
6493       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6494     }
6495   else
6496     {
6497       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6498                                         tree_view->priv->dy,
6499                                         &tree, &node);
6500
6501       if (tree == NULL)
6502         {
6503           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6504         }
6505       else
6506         {
6507           path = _gtk_tree_view_find_path (tree_view, tree, node);
6508           gtk_tree_view_set_top_row (tree_view, path, offset);
6509           gtk_tree_path_free (path);
6510         }
6511     }
6512 }
6513
6514 static void
6515 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6516 {
6517   GtkTreePath *path;
6518   GtkRBTree *tree;
6519   GtkRBNode *node;
6520   int new_dy;
6521
6522   /* Avoid recursive calls */
6523   if (tree_view->priv->in_top_row_to_dy)
6524     return;
6525
6526   if (tree_view->priv->top_row)
6527     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6528   else
6529     path = NULL;
6530
6531   if (!path)
6532     tree = NULL;
6533   else
6534     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6535
6536   if (path)
6537     gtk_tree_path_free (path);
6538
6539   if (tree == NULL)
6540     {
6541       /* keep dy and set new toprow */
6542       gtk_tree_row_reference_free (tree_view->priv->top_row);
6543       tree_view->priv->top_row = NULL;
6544       tree_view->priv->top_row_dy = 0;
6545       /* DO NOT install the idle handler */
6546       gtk_tree_view_dy_to_top_row (tree_view);
6547       return;
6548     }
6549
6550   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6551       < tree_view->priv->top_row_dy)
6552     {
6553       /* new top row -- do NOT install the idle handler */
6554       gtk_tree_view_dy_to_top_row (tree_view);
6555       return;
6556     }
6557
6558   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6559   new_dy += tree_view->priv->top_row_dy;
6560
6561   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6562     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6563
6564   new_dy = MAX (0, new_dy);
6565
6566   tree_view->priv->in_top_row_to_dy = TRUE;
6567   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6568   tree_view->priv->in_top_row_to_dy = FALSE;
6569 }
6570
6571
6572 void
6573 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6574 {
6575   tree_view->priv->mark_rows_col_dirty = TRUE;
6576
6577   install_presize_handler (tree_view);
6578 }
6579
6580 /*
6581  * This function works synchronously (due to the while (validate_rows...)
6582  * loop).
6583  *
6584  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6585  * here. You now need to check that yourself.
6586  */
6587 void
6588 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6589                                 GtkTreeViewColumn *column)
6590 {
6591   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6592   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6593
6594   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6595
6596   do_presize_handler (tree_view);
6597   while (validate_rows (tree_view));
6598
6599   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6600 }
6601
6602 /* Drag-and-drop */
6603
6604 static void
6605 set_source_row (GdkDragContext *context,
6606                 GtkTreeModel   *model,
6607                 GtkTreePath    *source_row)
6608 {
6609   g_object_set_data_full (G_OBJECT (context),
6610                           I_("gtk-tree-view-source-row"),
6611                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6612                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6613 }
6614
6615 static GtkTreePath*
6616 get_source_row (GdkDragContext *context)
6617 {
6618   GtkTreeRowReference *ref =
6619     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6620
6621   if (ref)
6622     return gtk_tree_row_reference_get_path (ref);
6623   else
6624     return NULL;
6625 }
6626
6627 typedef struct
6628 {
6629   GtkTreeRowReference *dest_row;
6630   guint                path_down_mode   : 1;
6631   guint                empty_view_drop  : 1;
6632   guint                drop_append_mode : 1;
6633 }
6634 DestRow;
6635
6636 static void
6637 dest_row_free (gpointer data)
6638 {
6639   DestRow *dr = (DestRow *)data;
6640
6641   gtk_tree_row_reference_free (dr->dest_row);
6642   g_slice_free (DestRow, dr);
6643 }
6644
6645 static void
6646 set_dest_row (GdkDragContext *context,
6647               GtkTreeModel   *model,
6648               GtkTreePath    *dest_row,
6649               gboolean        path_down_mode,
6650               gboolean        empty_view_drop,
6651               gboolean        drop_append_mode)
6652 {
6653   DestRow *dr;
6654
6655   if (!dest_row)
6656     {
6657       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6658                               NULL, NULL);
6659       return;
6660     }
6661
6662   dr = g_slice_new (DestRow);
6663
6664   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6665   dr->path_down_mode = path_down_mode != FALSE;
6666   dr->empty_view_drop = empty_view_drop != FALSE;
6667   dr->drop_append_mode = drop_append_mode != FALSE;
6668
6669   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6670                           dr, (GDestroyNotify) dest_row_free);
6671 }
6672
6673 static GtkTreePath*
6674 get_dest_row (GdkDragContext *context,
6675               gboolean       *path_down_mode)
6676 {
6677   DestRow *dr =
6678     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6679
6680   if (dr)
6681     {
6682       GtkTreePath *path = NULL;
6683
6684       if (path_down_mode)
6685         *path_down_mode = dr->path_down_mode;
6686
6687       if (dr->dest_row)
6688         path = gtk_tree_row_reference_get_path (dr->dest_row);
6689       else if (dr->empty_view_drop)
6690         path = gtk_tree_path_new_from_indices (0, -1);
6691       else
6692         path = NULL;
6693
6694       if (path && dr->drop_append_mode)
6695         gtk_tree_path_next (path);
6696
6697       return path;
6698     }
6699   else
6700     return NULL;
6701 }
6702
6703 /* Get/set whether drag_motion requested the drag data and
6704  * drag_data_received should thus not actually insert the data,
6705  * since the data doesn't result from a drop.
6706  */
6707 static void
6708 set_status_pending (GdkDragContext *context,
6709                     GdkDragAction   suggested_action)
6710 {
6711   g_object_set_data (G_OBJECT (context),
6712                      I_("gtk-tree-view-status-pending"),
6713                      GINT_TO_POINTER (suggested_action));
6714 }
6715
6716 static GdkDragAction
6717 get_status_pending (GdkDragContext *context)
6718 {
6719   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6720                                              "gtk-tree-view-status-pending"));
6721 }
6722
6723 static TreeViewDragInfo*
6724 get_info (GtkTreeView *tree_view)
6725 {
6726   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6727 }
6728
6729 static void
6730 destroy_info (TreeViewDragInfo *di)
6731 {
6732   g_slice_free (TreeViewDragInfo, di);
6733 }
6734
6735 static TreeViewDragInfo*
6736 ensure_info (GtkTreeView *tree_view)
6737 {
6738   TreeViewDragInfo *di;
6739
6740   di = get_info (tree_view);
6741
6742   if (di == NULL)
6743     {
6744       di = g_slice_new0 (TreeViewDragInfo);
6745
6746       g_object_set_data_full (G_OBJECT (tree_view),
6747                               I_("gtk-tree-view-drag-info"),
6748                               di,
6749                               (GDestroyNotify) destroy_info);
6750     }
6751
6752   return di;
6753 }
6754
6755 static void
6756 remove_info (GtkTreeView *tree_view)
6757 {
6758   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6759 }
6760
6761 #if 0
6762 static gint
6763 drag_scan_timeout (gpointer data)
6764 {
6765   GtkTreeView *tree_view;
6766   gint x, y;
6767   GdkModifierType state;
6768   GtkTreePath *path = NULL;
6769   GtkTreeViewColumn *column = NULL;
6770   GdkRectangle visible_rect;
6771
6772   GDK_THREADS_ENTER ();
6773
6774   tree_view = GTK_TREE_VIEW (data);
6775
6776   gdk_window_get_pointer (tree_view->priv->bin_window,
6777                           &x, &y, &state);
6778
6779   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6780
6781   /* See if we are near the edge. */
6782   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6783       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6784       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6785       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6786     {
6787       gtk_tree_view_get_path_at_pos (tree_view,
6788                                      tree_view->priv->bin_window,
6789                                      x, y,
6790                                      &path,
6791                                      &column,
6792                                      NULL,
6793                                      NULL);
6794
6795       if (path != NULL)
6796         {
6797           gtk_tree_view_scroll_to_cell (tree_view,
6798                                         path,
6799                                         column,
6800                                         TRUE,
6801                                         0.5, 0.5);
6802
6803           gtk_tree_path_free (path);
6804         }
6805     }
6806
6807   GDK_THREADS_LEAVE ();
6808
6809   return TRUE;
6810 }
6811 #endif /* 0 */
6812
6813 static void
6814 add_scroll_timeout (GtkTreeView *tree_view)
6815 {
6816   if (tree_view->priv->scroll_timeout == 0)
6817     {
6818       tree_view->priv->scroll_timeout =
6819         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6820     }
6821 }
6822
6823 static void
6824 remove_scroll_timeout (GtkTreeView *tree_view)
6825 {
6826   if (tree_view->priv->scroll_timeout != 0)
6827     {
6828       g_source_remove (tree_view->priv->scroll_timeout);
6829       tree_view->priv->scroll_timeout = 0;
6830     }
6831 }
6832
6833 static gboolean
6834 check_model_dnd (GtkTreeModel *model,
6835                  GType         required_iface,
6836                  const gchar  *signal)
6837 {
6838   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6839     {
6840       g_warning ("You must override the default '%s' handler "
6841                  "on GtkTreeView when using models that don't support "
6842                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6843                  "is to connect to '%s' and call "
6844                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6845                  "the default handler from running. Look at the source code "
6846                  "for the default handler in gtktreeview.c to get an idea what "
6847                  "your handler should do. (gtktreeview.c is in the GTK source "
6848                  "code.) If you're using GTK from a language other than C, "
6849                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6850                  signal, g_type_name (required_iface), signal);
6851       return FALSE;
6852     }
6853   else
6854     return TRUE;
6855 }
6856
6857 static void
6858 remove_open_timeout (GtkTreeView *tree_view)
6859 {
6860   if (tree_view->priv->open_dest_timeout != 0)
6861     {
6862       g_source_remove (tree_view->priv->open_dest_timeout);
6863       tree_view->priv->open_dest_timeout = 0;
6864     }
6865 }
6866
6867
6868 static gint
6869 open_row_timeout (gpointer data)
6870 {
6871   GtkTreeView *tree_view = data;
6872   GtkTreePath *dest_path = NULL;
6873   GtkTreeViewDropPosition pos;
6874   gboolean result = FALSE;
6875
6876   gtk_tree_view_get_drag_dest_row (tree_view,
6877                                    &dest_path,
6878                                    &pos);
6879
6880   if (dest_path &&
6881       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6882        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6883     {
6884       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6885       tree_view->priv->open_dest_timeout = 0;
6886
6887       gtk_tree_path_free (dest_path);
6888     }
6889   else
6890     {
6891       if (dest_path)
6892         gtk_tree_path_free (dest_path);
6893
6894       result = TRUE;
6895     }
6896
6897   return result;
6898 }
6899
6900 static gboolean
6901 scroll_row_timeout (gpointer data)
6902 {
6903   GtkTreeView *tree_view = data;
6904
6905   gtk_tree_view_vertical_autoscroll (tree_view);
6906
6907   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6908     gtk_tree_view_update_rubber_band (tree_view);
6909
6910   return TRUE;
6911 }
6912
6913 /* Returns TRUE if event should not be propagated to parent widgets */
6914 static gboolean
6915 set_destination_row (GtkTreeView    *tree_view,
6916                      GdkDragContext *context,
6917                      /* coordinates relative to the widget */
6918                      gint            x,
6919                      gint            y,
6920                      GdkDragAction  *suggested_action,
6921                      GdkAtom        *target)
6922 {
6923   GtkTreePath *path = NULL;
6924   GtkTreeViewDropPosition pos;
6925   GtkTreeViewDropPosition old_pos;
6926   TreeViewDragInfo *di;
6927   GtkWidget *widget;
6928   GtkTreePath *old_dest_path = NULL;
6929   gboolean can_drop = FALSE;
6930
6931   *suggested_action = 0;
6932   *target = GDK_NONE;
6933
6934   widget = GTK_WIDGET (tree_view);
6935
6936   di = get_info (tree_view);
6937
6938   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6939     {
6940       /* someone unset us as a drag dest, note that if
6941        * we return FALSE drag_leave isn't called
6942        */
6943
6944       gtk_tree_view_set_drag_dest_row (tree_view,
6945                                        NULL,
6946                                        GTK_TREE_VIEW_DROP_BEFORE);
6947
6948       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6949       remove_open_timeout (GTK_TREE_VIEW (widget));
6950
6951       return FALSE; /* no longer a drop site */
6952     }
6953
6954   *target = gtk_drag_dest_find_target (widget, context,
6955                                        gtk_drag_dest_get_target_list (widget));
6956   if (*target == GDK_NONE)
6957     {
6958       return FALSE;
6959     }
6960
6961   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6962                                           x, y,
6963                                           &path,
6964                                           &pos))
6965     {
6966       gint n_children;
6967       GtkTreeModel *model;
6968
6969       remove_open_timeout (tree_view);
6970
6971       /* the row got dropped on empty space, let's setup a special case
6972        */
6973
6974       if (path)
6975         gtk_tree_path_free (path);
6976
6977       model = gtk_tree_view_get_model (tree_view);
6978
6979       n_children = gtk_tree_model_iter_n_children (model, NULL);
6980       if (n_children)
6981         {
6982           pos = GTK_TREE_VIEW_DROP_AFTER;
6983           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6984         }
6985       else
6986         {
6987           pos = GTK_TREE_VIEW_DROP_BEFORE;
6988           path = gtk_tree_path_new_from_indices (0, -1);
6989         }
6990
6991       can_drop = TRUE;
6992
6993       goto out;
6994     }
6995
6996   g_assert (path);
6997
6998   /* If we left the current row's "open" zone, unset the timeout for
6999    * opening the row
7000    */
7001   gtk_tree_view_get_drag_dest_row (tree_view,
7002                                    &old_dest_path,
7003                                    &old_pos);
7004
7005   if (old_dest_path &&
7006       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7007        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7008          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7009     remove_open_timeout (tree_view);
7010
7011   if (old_dest_path)
7012     gtk_tree_path_free (old_dest_path);
7013
7014   if (TRUE /* FIXME if the location droppable predicate */)
7015     {
7016       can_drop = TRUE;
7017     }
7018
7019 out:
7020   if (can_drop)
7021     {
7022       GtkWidget *source_widget;
7023
7024       *suggested_action = context->suggested_action;
7025       source_widget = gtk_drag_get_source_widget (context);
7026
7027       if (source_widget == widget)
7028         {
7029           /* Default to MOVE, unless the user has
7030            * pressed ctrl or shift to affect available actions
7031            */
7032           if ((context->actions & GDK_ACTION_MOVE) != 0)
7033             *suggested_action = GDK_ACTION_MOVE;
7034         }
7035
7036       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7037                                        path, pos);
7038     }
7039   else
7040     {
7041       /* can't drop here */
7042       remove_open_timeout (tree_view);
7043
7044       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7045                                        NULL,
7046                                        GTK_TREE_VIEW_DROP_BEFORE);
7047     }
7048
7049   if (path)
7050     gtk_tree_path_free (path);
7051
7052   return TRUE;
7053 }
7054
7055 static GtkTreePath*
7056 get_logical_dest_row (GtkTreeView *tree_view,
7057                       gboolean    *path_down_mode,
7058                       gboolean    *drop_append_mode)
7059 {
7060   /* adjust path to point to the row the drop goes in front of */
7061   GtkTreePath *path = NULL;
7062   GtkTreeViewDropPosition pos;
7063
7064   g_return_val_if_fail (path_down_mode != NULL, NULL);
7065   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7066
7067   *path_down_mode = FALSE;
7068   *drop_append_mode = 0;
7069
7070   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7071
7072   if (path == NULL)
7073     return NULL;
7074
7075   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7076     ; /* do nothing */
7077   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7078            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7079     *path_down_mode = TRUE;
7080   else
7081     {
7082       GtkTreeIter iter;
7083       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7084
7085       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7086
7087       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7088           !gtk_tree_model_iter_next (model, &iter))
7089         *drop_append_mode = 1;
7090       else
7091         {
7092           *drop_append_mode = 0;
7093           gtk_tree_path_next (path);
7094         }
7095     }
7096
7097   return path;
7098 }
7099
7100 static gboolean
7101 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7102                                         GdkEventMotion   *event)
7103 {
7104   GtkWidget *widget = GTK_WIDGET (tree_view);
7105   GdkDragContext *context;
7106   TreeViewDragInfo *di;
7107   GtkTreePath *path = NULL;
7108   gint button;
7109   gint cell_x, cell_y;
7110   GtkTreeModel *model;
7111   gboolean retval = FALSE;
7112
7113   di = get_info (tree_view);
7114
7115   if (di == NULL || !di->source_set)
7116     goto out;
7117
7118   if (tree_view->priv->pressed_button < 0)
7119     goto out;
7120
7121   if (!gtk_drag_check_threshold (widget,
7122                                  tree_view->priv->press_start_x,
7123                                  tree_view->priv->press_start_y,
7124                                  event->x, event->y))
7125     goto out;
7126
7127   model = gtk_tree_view_get_model (tree_view);
7128
7129   if (model == NULL)
7130     goto out;
7131
7132   button = tree_view->priv->pressed_button;
7133   tree_view->priv->pressed_button = -1;
7134
7135   gtk_tree_view_get_path_at_pos (tree_view,
7136                                  tree_view->priv->press_start_x,
7137                                  tree_view->priv->press_start_y,
7138                                  &path,
7139                                  NULL,
7140                                  &cell_x,
7141                                  &cell_y);
7142
7143   if (path == NULL)
7144     goto out;
7145
7146   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7147       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7148                                            path))
7149     goto out;
7150
7151   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7152     goto out;
7153
7154   /* Now we can begin the drag */
7155
7156   retval = TRUE;
7157
7158   context = gtk_drag_begin (widget,
7159                             gtk_drag_source_get_target_list (widget),
7160                             di->source_actions,
7161                             button,
7162                             (GdkEvent*)event);
7163
7164   set_source_row (context, model, path);
7165
7166  out:
7167   if (path)
7168     gtk_tree_path_free (path);
7169
7170   return retval;
7171 }
7172
7173
7174 static void
7175 gtk_tree_view_drag_begin (GtkWidget      *widget,
7176                           GdkDragContext *context)
7177 {
7178   GtkTreeView *tree_view;
7179   GtkTreePath *path = NULL;
7180   gint cell_x, cell_y;
7181   cairo_surface_t *row_pix;
7182   TreeViewDragInfo *di;
7183
7184   tree_view = GTK_TREE_VIEW (widget);
7185
7186   /* if the user uses a custom DND source impl, we don't set the icon here */
7187   di = get_info (tree_view);
7188
7189   if (di == NULL || !di->source_set)
7190     return;
7191
7192   gtk_tree_view_get_path_at_pos (tree_view,
7193                                  tree_view->priv->press_start_x,
7194                                  tree_view->priv->press_start_y,
7195                                  &path,
7196                                  NULL,
7197                                  &cell_x,
7198                                  &cell_y);
7199
7200   g_return_if_fail (path != NULL);
7201
7202   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7203                                                 path);
7204   cairo_surface_set_device_offset (row_pix,
7205                                    /* the + 1 is for the black border in the icon */
7206                                    - (tree_view->priv->press_start_x + 1),
7207                                    - (cell_y + 1));
7208
7209   gtk_drag_set_icon_surface (context, row_pix);
7210
7211   cairo_surface_destroy (row_pix);
7212   gtk_tree_path_free (path);
7213 }
7214
7215 static void
7216 gtk_tree_view_drag_end (GtkWidget      *widget,
7217                         GdkDragContext *context)
7218 {
7219   /* do nothing */
7220 }
7221
7222 /* Default signal implementations for the drag signals */
7223 static void
7224 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7225                              GdkDragContext   *context,
7226                              GtkSelectionData *selection_data,
7227                              guint             info,
7228                              guint             time)
7229 {
7230   GtkTreeView *tree_view;
7231   GtkTreeModel *model;
7232   TreeViewDragInfo *di;
7233   GtkTreePath *source_row;
7234
7235   tree_view = GTK_TREE_VIEW (widget);
7236
7237   model = gtk_tree_view_get_model (tree_view);
7238
7239   if (model == NULL)
7240     return;
7241
7242   di = get_info (GTK_TREE_VIEW (widget));
7243
7244   if (di == NULL)
7245     return;
7246
7247   source_row = get_source_row (context);
7248
7249   if (source_row == NULL)
7250     return;
7251
7252   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7253    * any model; for DragSource models there are some other targets
7254    * we also support.
7255    */
7256
7257   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7258       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7259                                           source_row,
7260                                           selection_data))
7261     goto done;
7262
7263   /* If drag_data_get does nothing, try providing row data. */
7264   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7265     {
7266       gtk_tree_set_row_drag_data (selection_data,
7267                                   model,
7268                                   source_row);
7269     }
7270
7271  done:
7272   gtk_tree_path_free (source_row);
7273 }
7274
7275
7276 static void
7277 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7278                                 GdkDragContext *context)
7279 {
7280   TreeViewDragInfo *di;
7281   GtkTreeModel *model;
7282   GtkTreeView *tree_view;
7283   GtkTreePath *source_row;
7284
7285   tree_view = GTK_TREE_VIEW (widget);
7286   model = gtk_tree_view_get_model (tree_view);
7287
7288   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7289     return;
7290
7291   di = get_info (tree_view);
7292
7293   if (di == NULL)
7294     return;
7295
7296   source_row = get_source_row (context);
7297
7298   if (source_row == NULL)
7299     return;
7300
7301   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7302                                          source_row);
7303
7304   gtk_tree_path_free (source_row);
7305
7306   set_source_row (context, NULL, NULL);
7307 }
7308
7309 static void
7310 gtk_tree_view_drag_leave (GtkWidget      *widget,
7311                           GdkDragContext *context,
7312                           guint             time)
7313 {
7314   /* unset any highlight row */
7315   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7316                                    NULL,
7317                                    GTK_TREE_VIEW_DROP_BEFORE);
7318
7319   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7320   remove_open_timeout (GTK_TREE_VIEW (widget));
7321 }
7322
7323
7324 static gboolean
7325 gtk_tree_view_drag_motion (GtkWidget        *widget,
7326                            GdkDragContext   *context,
7327                            /* coordinates relative to the widget */
7328                            gint              x,
7329                            gint              y,
7330                            guint             time)
7331 {
7332   gboolean empty;
7333   GtkTreePath *path = NULL;
7334   GtkTreeViewDropPosition pos;
7335   GtkTreeView *tree_view;
7336   GdkDragAction suggested_action = 0;
7337   GdkAtom target;
7338
7339   tree_view = GTK_TREE_VIEW (widget);
7340
7341   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7342     return FALSE;
7343
7344   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7345
7346   /* we only know this *after* set_desination_row */
7347   empty = tree_view->priv->empty_view_drop;
7348
7349   if (path == NULL && !empty)
7350     {
7351       /* Can't drop here. */
7352       gdk_drag_status (context, 0, time);
7353     }
7354   else
7355     {
7356       if (tree_view->priv->open_dest_timeout == 0 &&
7357           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7358            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7359         {
7360           tree_view->priv->open_dest_timeout =
7361             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7362         }
7363       else
7364         {
7365           add_scroll_timeout (tree_view);
7366         }
7367
7368       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7369         {
7370           /* Request data so we can use the source row when
7371            * determining whether to accept the drop
7372            */
7373           set_status_pending (context, suggested_action);
7374           gtk_drag_get_data (widget, context, target, time);
7375         }
7376       else
7377         {
7378           set_status_pending (context, 0);
7379           gdk_drag_status (context, suggested_action, time);
7380         }
7381     }
7382
7383   if (path)
7384     gtk_tree_path_free (path);
7385
7386   return TRUE;
7387 }
7388
7389
7390 static gboolean
7391 gtk_tree_view_drag_drop (GtkWidget        *widget,
7392                          GdkDragContext   *context,
7393                          /* coordinates relative to the widget */
7394                          gint              x,
7395                          gint              y,
7396                          guint             time)
7397 {
7398   GtkTreeView *tree_view;
7399   GtkTreePath *path;
7400   GdkDragAction suggested_action = 0;
7401   GdkAtom target = GDK_NONE;
7402   TreeViewDragInfo *di;
7403   GtkTreeModel *model;
7404   gboolean path_down_mode;
7405   gboolean drop_append_mode;
7406
7407   tree_view = GTK_TREE_VIEW (widget);
7408
7409   model = gtk_tree_view_get_model (tree_view);
7410
7411   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7412   remove_open_timeout (GTK_TREE_VIEW (widget));
7413
7414   di = get_info (tree_view);
7415
7416   if (di == NULL)
7417     return FALSE;
7418
7419   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7420     return FALSE;
7421
7422   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7423     return FALSE;
7424
7425   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7426
7427   if (target != GDK_NONE && path != NULL)
7428     {
7429       /* in case a motion had requested drag data, change things so we
7430        * treat drag data receives as a drop.
7431        */
7432       set_status_pending (context, 0);
7433       set_dest_row (context, model, path,
7434                     path_down_mode, tree_view->priv->empty_view_drop,
7435                     drop_append_mode);
7436     }
7437
7438   if (path)
7439     gtk_tree_path_free (path);
7440
7441   /* Unset this thing */
7442   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7443                                    NULL,
7444                                    GTK_TREE_VIEW_DROP_BEFORE);
7445
7446   if (target != GDK_NONE)
7447     {
7448       gtk_drag_get_data (widget, context, target, time);
7449       return TRUE;
7450     }
7451   else
7452     return FALSE;
7453 }
7454
7455 static void
7456 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7457                                   GdkDragContext   *context,
7458                                   /* coordinates relative to the widget */
7459                                   gint              x,
7460                                   gint              y,
7461                                   GtkSelectionData *selection_data,
7462                                   guint             info,
7463                                   guint             time)
7464 {
7465   GtkTreePath *path;
7466   TreeViewDragInfo *di;
7467   gboolean accepted = FALSE;
7468   GtkTreeModel *model;
7469   GtkTreeView *tree_view;
7470   GtkTreePath *dest_row;
7471   GdkDragAction suggested_action;
7472   gboolean path_down_mode;
7473   gboolean drop_append_mode;
7474
7475   tree_view = GTK_TREE_VIEW (widget);
7476
7477   model = gtk_tree_view_get_model (tree_view);
7478
7479   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7480     return;
7481
7482   di = get_info (tree_view);
7483
7484   if (di == NULL)
7485     return;
7486
7487   suggested_action = get_status_pending (context);
7488
7489   if (suggested_action)
7490     {
7491       /* We are getting this data due to a request in drag_motion,
7492        * rather than due to a request in drag_drop, so we are just
7493        * supposed to call drag_status, not actually paste in the
7494        * data.
7495        */
7496       path = get_logical_dest_row (tree_view, &path_down_mode,
7497                                    &drop_append_mode);
7498
7499       if (path == NULL)
7500         suggested_action = 0;
7501       else if (path_down_mode)
7502         gtk_tree_path_down (path);
7503
7504       if (suggested_action)
7505         {
7506           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7507                                                      path,
7508                                                      selection_data))
7509             {
7510               if (path_down_mode)
7511                 {
7512                   path_down_mode = FALSE;
7513                   gtk_tree_path_up (path);
7514
7515                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7516                                                              path,
7517                                                              selection_data))
7518                     suggested_action = 0;
7519                 }
7520               else
7521                 suggested_action = 0;
7522             }
7523         }
7524
7525       gdk_drag_status (context, suggested_action, time);
7526
7527       if (path)
7528         gtk_tree_path_free (path);
7529
7530       /* If you can't drop, remove user drop indicator until the next motion */
7531       if (suggested_action == 0)
7532         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7533                                          NULL,
7534                                          GTK_TREE_VIEW_DROP_BEFORE);
7535
7536       return;
7537     }
7538
7539   dest_row = get_dest_row (context, &path_down_mode);
7540
7541   if (dest_row == NULL)
7542     return;
7543
7544   if (selection_data->length >= 0)
7545     {
7546       if (path_down_mode)
7547         {
7548           gtk_tree_path_down (dest_row);
7549           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7550                                                      dest_row, selection_data))
7551             gtk_tree_path_up (dest_row);
7552         }
7553     }
7554
7555   if (selection_data->length >= 0)
7556     {
7557       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7558                                                  dest_row,
7559                                                  selection_data))
7560         accepted = TRUE;
7561     }
7562
7563   gtk_drag_finish (context,
7564                    accepted,
7565                    (context->action == GDK_ACTION_MOVE),
7566                    time);
7567
7568   if (gtk_tree_path_get_depth (dest_row) == 1
7569       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7570     {
7571       /* special special case drag to "0", scroll to first item */
7572       if (!tree_view->priv->scroll_to_path)
7573         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7574     }
7575
7576   gtk_tree_path_free (dest_row);
7577
7578   /* drop dest_row */
7579   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7580 }
7581
7582
7583
7584 /* GtkContainer Methods
7585  */
7586
7587
7588 static void
7589 gtk_tree_view_remove (GtkContainer *container,
7590                       GtkWidget    *widget)
7591 {
7592   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7593   GtkTreeViewChild *child = NULL;
7594   GList *tmp_list;
7595
7596   tmp_list = tree_view->priv->children;
7597   while (tmp_list)
7598     {
7599       child = tmp_list->data;
7600       if (child->widget == widget)
7601         {
7602           gtk_widget_unparent (widget);
7603
7604           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7605           g_list_free_1 (tmp_list);
7606           g_slice_free (GtkTreeViewChild, child);
7607           return;
7608         }
7609
7610       tmp_list = tmp_list->next;
7611     }
7612
7613   tmp_list = tree_view->priv->columns;
7614
7615   while (tmp_list)
7616     {
7617       GtkTreeViewColumn *column;
7618       column = tmp_list->data;
7619       if (column->button == widget)
7620         {
7621           gtk_widget_unparent (widget);
7622           return;
7623         }
7624       tmp_list = tmp_list->next;
7625     }
7626 }
7627
7628 static void
7629 gtk_tree_view_forall (GtkContainer *container,
7630                       gboolean      include_internals,
7631                       GtkCallback   callback,
7632                       gpointer      callback_data)
7633 {
7634   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7635   GtkTreeViewChild *child = NULL;
7636   GtkTreeViewColumn *column;
7637   GList *tmp_list;
7638
7639   tmp_list = tree_view->priv->children;
7640   while (tmp_list)
7641     {
7642       child = tmp_list->data;
7643       tmp_list = tmp_list->next;
7644
7645       (* callback) (child->widget, callback_data);
7646     }
7647   if (include_internals == FALSE)
7648     return;
7649
7650   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7651     {
7652       column = tmp_list->data;
7653
7654       if (column->button)
7655         (* callback) (column->button, callback_data);
7656     }
7657 }
7658
7659 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7660  * cells. If so we draw one big row-spanning focus rectangle.
7661  */
7662 static gboolean
7663 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7664 {
7665   GList *list;
7666
7667   for (list = tree_view->priv->columns; list; list = list->next)
7668     {
7669       if (!((GtkTreeViewColumn *)list->data)->visible)
7670         continue;
7671       if (_gtk_tree_view_column_count_special_cells (list->data))
7672         return TRUE;
7673     }
7674
7675   return FALSE;
7676 }
7677
7678 static void
7679 column_sizing_notify (GObject    *object,
7680                       GParamSpec *pspec,
7681                       gpointer    data)
7682 {
7683   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7684
7685   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7686     /* disable fixed height mode */
7687     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7688 }
7689
7690 /**
7691  * gtk_tree_view_set_fixed_height_mode:
7692  * @tree_view: a #GtkTreeView 
7693  * @enable: %TRUE to enable fixed height mode
7694  * 
7695  * Enables or disables the fixed height mode of @tree_view. 
7696  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7697  * rows have the same height. 
7698  * Only enable this option if all rows are the same height and all
7699  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7700  *
7701  * Since: 2.6 
7702  **/
7703 void
7704 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7705                                      gboolean     enable)
7706 {
7707   GList *l;
7708   
7709   enable = enable != FALSE;
7710
7711   if (enable == tree_view->priv->fixed_height_mode)
7712     return;
7713
7714   if (!enable)
7715     {
7716       tree_view->priv->fixed_height_mode = 0;
7717       tree_view->priv->fixed_height = -1;
7718
7719       /* force a revalidation */
7720       install_presize_handler (tree_view);
7721     }
7722   else 
7723     {
7724       /* make sure all columns are of type FIXED */
7725       for (l = tree_view->priv->columns; l; l = l->next)
7726         {
7727           GtkTreeViewColumn *c = l->data;
7728           
7729           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7730         }
7731       
7732       /* yes, we really have to do this is in a separate loop */
7733       for (l = tree_view->priv->columns; l; l = l->next)
7734         g_signal_connect (l->data, "notify::sizing",
7735                           G_CALLBACK (column_sizing_notify), tree_view);
7736       
7737       tree_view->priv->fixed_height_mode = 1;
7738       tree_view->priv->fixed_height = -1;
7739       
7740       if (tree_view->priv->tree)
7741         initialize_fixed_height_mode (tree_view);
7742     }
7743
7744   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7745 }
7746
7747 /**
7748  * gtk_tree_view_get_fixed_height_mode:
7749  * @tree_view: a #GtkTreeView
7750  * 
7751  * Returns whether fixed height mode is turned on for @tree_view.
7752  * 
7753  * Return value: %TRUE if @tree_view is in fixed height mode
7754  * 
7755  * Since: 2.6
7756  **/
7757 gboolean
7758 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7759 {
7760   return tree_view->priv->fixed_height_mode;
7761 }
7762
7763 /* Returns TRUE if the focus is within the headers, after the focus operation is
7764  * done
7765  */
7766 static gboolean
7767 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7768                             GtkDirectionType  dir,
7769                             gboolean          clamp_column_visible)
7770 {
7771   GtkWidget *focus_child;
7772
7773   GList *last_column, *first_column;
7774   GList *tmp_list;
7775   gboolean rtl;
7776
7777   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7778     return FALSE;
7779
7780   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7781
7782   first_column = tree_view->priv->columns;
7783   while (first_column)
7784     {
7785       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7786           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7787           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7788            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7789         break;
7790       first_column = first_column->next;
7791     }
7792
7793   /* No headers are visible, or are focusable.  We can't focus in or out.
7794    */
7795   if (first_column == NULL)
7796     return FALSE;
7797
7798   last_column = g_list_last (tree_view->priv->columns);
7799   while (last_column)
7800     {
7801       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7802           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7803           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7804            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7805         break;
7806       last_column = last_column->prev;
7807     }
7808
7809
7810   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7811
7812   switch (dir)
7813     {
7814     case GTK_DIR_TAB_BACKWARD:
7815     case GTK_DIR_TAB_FORWARD:
7816     case GTK_DIR_UP:
7817     case GTK_DIR_DOWN:
7818       if (focus_child == NULL)
7819         {
7820           if (tree_view->priv->focus_column != NULL &&
7821               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7822             focus_child = tree_view->priv->focus_column->button;
7823           else
7824             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7825           gtk_widget_grab_focus (focus_child);
7826           break;
7827         }
7828       return FALSE;
7829
7830     case GTK_DIR_LEFT:
7831     case GTK_DIR_RIGHT:
7832       if (focus_child == NULL)
7833         {
7834           if (tree_view->priv->focus_column != NULL)
7835             focus_child = tree_view->priv->focus_column->button;
7836           else if (dir == GTK_DIR_LEFT)
7837             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7838           else
7839             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7840           gtk_widget_grab_focus (focus_child);
7841           break;
7842         }
7843
7844       if (gtk_widget_child_focus (focus_child, dir))
7845         {
7846           /* The focus moves inside the button. */
7847           /* This is probably a great example of bad UI */
7848           break;
7849         }
7850
7851       /* We need to move the focus among the row of buttons. */
7852       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7853         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7854           break;
7855
7856       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7857           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7858         {
7859           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7860           break;
7861         }
7862
7863       while (tmp_list)
7864         {
7865           GtkTreeViewColumn *column;
7866
7867           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7868             tmp_list = tmp_list->next;
7869           else
7870             tmp_list = tmp_list->prev;
7871
7872           if (tmp_list == NULL)
7873             {
7874               g_warning ("Internal button not found");
7875               break;
7876             }
7877           column = tmp_list->data;
7878           if (column->button &&
7879               column->visible &&
7880               gtk_widget_get_can_focus (column->button))
7881             {
7882               focus_child = column->button;
7883               gtk_widget_grab_focus (column->button);
7884               break;
7885             }
7886         }
7887       break;
7888     default:
7889       g_assert_not_reached ();
7890       break;
7891     }
7892
7893   /* if focus child is non-null, we assume it's been set to the current focus child
7894    */
7895   if (focus_child)
7896     {
7897       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7898         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7899           {
7900             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7901             break;
7902           }
7903
7904       if (clamp_column_visible)
7905         {
7906           gtk_tree_view_clamp_column_visible (tree_view,
7907                                               tree_view->priv->focus_column,
7908                                               FALSE);
7909         }
7910     }
7911
7912   return (focus_child != NULL);
7913 }
7914
7915 /* This function returns in 'path' the first focusable path, if the given path
7916  * is already focusable, it's the returned one.
7917  */
7918 static gboolean
7919 search_first_focusable_path (GtkTreeView  *tree_view,
7920                              GtkTreePath **path,
7921                              gboolean      search_forward,
7922                              GtkRBTree   **new_tree,
7923                              GtkRBNode   **new_node)
7924 {
7925   GtkRBTree *tree = NULL;
7926   GtkRBNode *node = NULL;
7927
7928   if (!path || !*path)
7929     return FALSE;
7930
7931   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7932
7933   if (!tree || !node)
7934     return FALSE;
7935
7936   while (node && row_is_separator (tree_view, NULL, *path))
7937     {
7938       if (search_forward)
7939         _gtk_rbtree_next_full (tree, node, &tree, &node);
7940       else
7941         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7942
7943       if (*path)
7944         gtk_tree_path_free (*path);
7945
7946       if (node)
7947         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7948       else
7949         *path = NULL;
7950     }
7951
7952   if (new_tree)
7953     *new_tree = tree;
7954
7955   if (new_node)
7956     *new_node = node;
7957
7958   return (*path != NULL);
7959 }
7960
7961 static gint
7962 gtk_tree_view_focus (GtkWidget        *widget,
7963                      GtkDirectionType  direction)
7964 {
7965   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7966   GtkContainer *container = GTK_CONTAINER (widget);
7967   GtkWidget *focus_child;
7968
7969   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
7970     return FALSE;
7971
7972   focus_child = gtk_container_get_focus_child (container);
7973
7974   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7975   /* Case 1.  Headers currently have focus. */
7976   if (focus_child)
7977     {
7978       switch (direction)
7979         {
7980         case GTK_DIR_LEFT:
7981         case GTK_DIR_RIGHT:
7982           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7983           return TRUE;
7984         case GTK_DIR_TAB_BACKWARD:
7985         case GTK_DIR_UP:
7986           return FALSE;
7987         case GTK_DIR_TAB_FORWARD:
7988         case GTK_DIR_DOWN:
7989           gtk_widget_grab_focus (widget);
7990           return TRUE;
7991         default:
7992           g_assert_not_reached ();
7993           return FALSE;
7994         }
7995     }
7996
7997   /* Case 2. We don't have focus at all. */
7998   if (!gtk_widget_has_focus (widget))
7999     {
8000       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
8001         gtk_widget_grab_focus (widget);
8002       return TRUE;
8003     }
8004
8005   /* Case 3. We have focus already. */
8006   if (direction == GTK_DIR_TAB_BACKWARD)
8007     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8008   else if (direction == GTK_DIR_TAB_FORWARD)
8009     return FALSE;
8010
8011   /* Other directions caught by the keybindings */
8012   gtk_widget_grab_focus (widget);
8013   return TRUE;
8014 }
8015
8016 static void
8017 gtk_tree_view_grab_focus (GtkWidget *widget)
8018 {
8019   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8020
8021   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8022 }
8023
8024 static void
8025 gtk_tree_view_style_set (GtkWidget *widget,
8026                          GtkStyle *previous_style)
8027 {
8028   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8029   GtkStyle *style;
8030   GList *list;
8031   GtkTreeViewColumn *column;
8032
8033   if (gtk_widget_get_realized (widget))
8034     {
8035       style = gtk_widget_get_style (widget);
8036       gdk_window_set_background (tree_view->priv->bin_window,
8037                                  &style->base[gtk_widget_get_state (widget)]);
8038       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8039
8040       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8041       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8042     }
8043
8044   gtk_widget_style_get (widget,
8045                         "expander-size", &tree_view->priv->expander_size,
8046                         NULL);
8047   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8048
8049   for (list = tree_view->priv->columns; list; list = list->next)
8050     {
8051       column = list->data;
8052       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8053     }
8054
8055   tree_view->priv->fixed_height = -1;
8056   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8057
8058   gtk_widget_queue_resize (widget);
8059 }
8060
8061
8062 static void
8063 gtk_tree_view_set_focus_child (GtkContainer *container,
8064                                GtkWidget    *child)
8065 {
8066   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8067   GList *list;
8068
8069   for (list = tree_view->priv->columns; list; list = list->next)
8070     {
8071       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8072         {
8073           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8074           break;
8075         }
8076     }
8077
8078   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8079 }
8080
8081 static void
8082 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
8083                                GtkAdjustment *hadj,
8084                                GtkAdjustment *vadj)
8085 {
8086   gboolean need_adjust = FALSE;
8087
8088   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8089
8090   if (hadj)
8091     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
8092   else
8093     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8094   if (vadj)
8095     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
8096   else
8097     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8098
8099   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8100     {
8101       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8102                                             gtk_tree_view_adjustment_changed,
8103                                             tree_view);
8104       g_object_unref (tree_view->priv->hadjustment);
8105     }
8106
8107   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8108     {
8109       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8110                                             gtk_tree_view_adjustment_changed,
8111                                             tree_view);
8112       g_object_unref (tree_view->priv->vadjustment);
8113     }
8114
8115   if (tree_view->priv->hadjustment != hadj)
8116     {
8117       tree_view->priv->hadjustment = hadj;
8118       g_object_ref_sink (tree_view->priv->hadjustment);
8119
8120       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8121                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8122                         tree_view);
8123       need_adjust = TRUE;
8124     }
8125
8126   if (tree_view->priv->vadjustment != vadj)
8127     {
8128       tree_view->priv->vadjustment = vadj;
8129       g_object_ref_sink (tree_view->priv->vadjustment);
8130
8131       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8132                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8133                         tree_view);
8134       need_adjust = TRUE;
8135     }
8136
8137   if (need_adjust)
8138     gtk_tree_view_adjustment_changed (NULL, tree_view);
8139 }
8140
8141
8142 static gboolean
8143 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8144                                 GtkMovementStep    step,
8145                                 gint               count)
8146 {
8147   GdkModifierType state;
8148
8149   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8150   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8151                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8152                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8153                         step == GTK_MOVEMENT_PAGES ||
8154                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8155
8156   if (tree_view->priv->tree == NULL)
8157     return FALSE;
8158   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8159     return FALSE;
8160
8161   gtk_tree_view_stop_editing (tree_view, FALSE);
8162   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8163   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8164
8165   if (gtk_get_current_event_state (&state))
8166     {
8167       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8168         tree_view->priv->ctrl_pressed = TRUE;
8169       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8170         tree_view->priv->shift_pressed = TRUE;
8171     }
8172   /* else we assume not pressed */
8173
8174   switch (step)
8175     {
8176       /* currently we make no distinction.  When we go bi-di, we need to */
8177     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8178     case GTK_MOVEMENT_VISUAL_POSITIONS:
8179       gtk_tree_view_move_cursor_left_right (tree_view, count);
8180       break;
8181     case GTK_MOVEMENT_DISPLAY_LINES:
8182       gtk_tree_view_move_cursor_up_down (tree_view, count);
8183       break;
8184     case GTK_MOVEMENT_PAGES:
8185       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8186       break;
8187     case GTK_MOVEMENT_BUFFER_ENDS:
8188       gtk_tree_view_move_cursor_start_end (tree_view, count);
8189       break;
8190     default:
8191       g_assert_not_reached ();
8192     }
8193
8194   tree_view->priv->ctrl_pressed = FALSE;
8195   tree_view->priv->shift_pressed = FALSE;
8196
8197   return TRUE;
8198 }
8199
8200 static void
8201 gtk_tree_view_put (GtkTreeView *tree_view,
8202                    GtkWidget   *child_widget,
8203                    /* in bin_window coordinates */
8204                    gint         x,
8205                    gint         y,
8206                    gint         width,
8207                    gint         height)
8208 {
8209   GtkTreeViewChild *child;
8210   
8211   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8212   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8213
8214   child = g_slice_new (GtkTreeViewChild);
8215
8216   child->widget = child_widget;
8217   child->x = x;
8218   child->y = y;
8219   child->width = width;
8220   child->height = height;
8221
8222   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8223
8224   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8225     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8226   
8227   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8228 }
8229
8230 void
8231 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8232                                   GtkWidget   *widget,
8233                                   /* in tree coordinates */
8234                                   gint         x,
8235                                   gint         y,
8236                                   gint         width,
8237                                   gint         height)
8238 {
8239   GtkTreeViewChild *child = NULL;
8240   GList *list;
8241   GdkRectangle allocation;
8242
8243   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8244   g_return_if_fail (GTK_IS_WIDGET (widget));
8245
8246   for (list = tree_view->priv->children; list; list = list->next)
8247     {
8248       if (((GtkTreeViewChild *)list->data)->widget == widget)
8249         {
8250           child = list->data;
8251           break;
8252         }
8253     }
8254   if (child == NULL)
8255     return;
8256
8257   allocation.x = child->x = x;
8258   allocation.y = child->y = y;
8259   allocation.width = child->width = width;
8260   allocation.height = child->height = height;
8261
8262   if (gtk_widget_get_realized (widget))
8263     gtk_widget_size_allocate (widget, &allocation);
8264 }
8265
8266
8267 /* TreeModel Callbacks
8268  */
8269
8270 static void
8271 gtk_tree_view_row_changed (GtkTreeModel *model,
8272                            GtkTreePath  *path,
8273                            GtkTreeIter  *iter,
8274                            gpointer      data)
8275 {
8276   GtkTreeView *tree_view = (GtkTreeView *)data;
8277   GtkRBTree *tree;
8278   GtkRBNode *node;
8279   gboolean free_path = FALSE;
8280   GList *list;
8281   GtkTreePath *cursor_path;
8282
8283   g_return_if_fail (path != NULL || iter != NULL);
8284
8285   if (tree_view->priv->cursor != NULL)
8286     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8287   else
8288     cursor_path = NULL;
8289
8290   if (tree_view->priv->edited_column &&
8291       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8292     gtk_tree_view_stop_editing (tree_view, TRUE);
8293
8294   if (cursor_path != NULL)
8295     gtk_tree_path_free (cursor_path);
8296
8297   if (path == NULL)
8298     {
8299       path = gtk_tree_model_get_path (model, iter);
8300       free_path = TRUE;
8301     }
8302   else if (iter == NULL)
8303     gtk_tree_model_get_iter (model, iter, path);
8304
8305   if (_gtk_tree_view_find_node (tree_view,
8306                                 path,
8307                                 &tree,
8308                                 &node))
8309     /* We aren't actually showing the node */
8310     goto done;
8311
8312   if (tree == NULL)
8313     goto done;
8314
8315   if (tree_view->priv->fixed_height_mode
8316       && tree_view->priv->fixed_height >= 0)
8317     {
8318       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8319       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8320         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8321     }
8322   else
8323     {
8324       _gtk_rbtree_node_mark_invalid (tree, node);
8325       for (list = tree_view->priv->columns; list; list = list->next)
8326         {
8327           GtkTreeViewColumn *column;
8328
8329           column = list->data;
8330           if (! column->visible)
8331             continue;
8332
8333           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8334             {
8335               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8336             }
8337         }
8338     }
8339
8340  done:
8341   if (!tree_view->priv->fixed_height_mode &&
8342       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8343     install_presize_handler (tree_view);
8344   if (free_path)
8345     gtk_tree_path_free (path);
8346 }
8347
8348 static void
8349 gtk_tree_view_row_inserted (GtkTreeModel *model,
8350                             GtkTreePath  *path,
8351                             GtkTreeIter  *iter,
8352                             gpointer      data)
8353 {
8354   GtkTreeView *tree_view = (GtkTreeView *) data;
8355   gint *indices;
8356   GtkRBTree *tmptree, *tree;
8357   GtkRBNode *tmpnode = NULL;
8358   gint depth;
8359   gint i = 0;
8360   gint height;
8361   gboolean free_path = FALSE;
8362   gboolean node_visible = TRUE;
8363
8364   g_return_if_fail (path != NULL || iter != NULL);
8365
8366   if (tree_view->priv->fixed_height_mode
8367       && tree_view->priv->fixed_height >= 0)
8368     height = tree_view->priv->fixed_height;
8369   else
8370     height = 0;
8371
8372   if (path == NULL)
8373     {
8374       path = gtk_tree_model_get_path (model, iter);
8375       free_path = TRUE;
8376     }
8377   else if (iter == NULL)
8378     gtk_tree_model_get_iter (model, iter, path);
8379
8380   if (tree_view->priv->tree == NULL)
8381     tree_view->priv->tree = _gtk_rbtree_new ();
8382
8383   tmptree = tree = tree_view->priv->tree;
8384
8385   /* Update all row-references */
8386   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8387   depth = gtk_tree_path_get_depth (path);
8388   indices = gtk_tree_path_get_indices (path);
8389
8390   /* First, find the parent tree */
8391   while (i < depth - 1)
8392     {
8393       if (tmptree == NULL)
8394         {
8395           /* We aren't showing the node */
8396           node_visible = FALSE;
8397           goto done;
8398         }
8399
8400       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8401       if (tmpnode == NULL)
8402         {
8403           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8404                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8405                      "before the parent was inserted.");
8406           goto done;
8407         }
8408       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8409         {
8410           /* FIXME enforce correct behavior on model, probably */
8411           /* In theory, the model should have emitted has_child_toggled here.  We
8412            * try to catch it anyway, just to be safe, in case the model hasn't.
8413            */
8414           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8415                                                            tree,
8416                                                            tmpnode);
8417           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8418           gtk_tree_path_free (tmppath);
8419           goto done;
8420         }
8421
8422       tmptree = tmpnode->children;
8423       tree = tmptree;
8424       i++;
8425     }
8426
8427   if (tree == NULL)
8428     {
8429       node_visible = FALSE;
8430       goto done;
8431     }
8432
8433   /* ref the node */
8434   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8435   if (indices[depth - 1] == 0)
8436     {
8437       tmpnode = _gtk_rbtree_find_count (tree, 1);
8438       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8439     }
8440   else
8441     {
8442       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8443       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8444     }
8445
8446  done:
8447   if (height > 0)
8448     {
8449       if (tree)
8450         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8451
8452       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8453         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8454       else
8455         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8456     }
8457   else
8458     install_presize_handler (tree_view);
8459   if (free_path)
8460     gtk_tree_path_free (path);
8461 }
8462
8463 static void
8464 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8465                                      GtkTreePath  *path,
8466                                      GtkTreeIter  *iter,
8467                                      gpointer      data)
8468 {
8469   GtkTreeView *tree_view = (GtkTreeView *)data;
8470   GtkTreeIter real_iter;
8471   gboolean has_child;
8472   GtkRBTree *tree;
8473   GtkRBNode *node;
8474   gboolean free_path = FALSE;
8475
8476   g_return_if_fail (path != NULL || iter != NULL);
8477
8478   if (iter)
8479     real_iter = *iter;
8480
8481   if (path == NULL)
8482     {
8483       path = gtk_tree_model_get_path (model, iter);
8484       free_path = TRUE;
8485     }
8486   else if (iter == NULL)
8487     gtk_tree_model_get_iter (model, &real_iter, path);
8488
8489   if (_gtk_tree_view_find_node (tree_view,
8490                                 path,
8491                                 &tree,
8492                                 &node))
8493     /* We aren't actually showing the node */
8494     goto done;
8495
8496   if (tree == NULL)
8497     goto done;
8498
8499   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8500   /* Sanity check.
8501    */
8502   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8503     goto done;
8504
8505   if (has_child)
8506     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8507   else
8508     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8509
8510   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8511     {
8512       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8513       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8514         {
8515           GList *list;
8516
8517           for (list = tree_view->priv->columns; list; list = list->next)
8518             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8519               {
8520                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8521                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8522                 break;
8523               }
8524         }
8525       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8526     }
8527   else
8528     {
8529       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8530     }
8531
8532  done:
8533   if (free_path)
8534     gtk_tree_path_free (path);
8535 }
8536
8537 static void
8538 count_children_helper (GtkRBTree *tree,
8539                        GtkRBNode *node,
8540                        gpointer   data)
8541 {
8542   if (node->children)
8543     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8544   (*((gint *)data))++;
8545 }
8546
8547 static void
8548 check_selection_helper (GtkRBTree *tree,
8549                         GtkRBNode *node,
8550                         gpointer   data)
8551 {
8552   gint *value = (gint *)data;
8553
8554   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8555
8556   if (node->children && !*value)
8557     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8558 }
8559
8560 static void
8561 gtk_tree_view_row_deleted (GtkTreeModel *model,
8562                            GtkTreePath  *path,
8563                            gpointer      data)
8564 {
8565   GtkTreeView *tree_view = (GtkTreeView *)data;
8566   GtkRBTree *tree;
8567   GtkRBNode *node;
8568   GList *list;
8569   gint selection_changed = FALSE;
8570
8571   g_return_if_fail (path != NULL);
8572
8573   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8574
8575   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8576     return;
8577
8578   if (tree == NULL)
8579     return;
8580
8581   /* check if the selection has been changed */
8582   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8583                         check_selection_helper, &selection_changed);
8584
8585   for (list = tree_view->priv->columns; list; list = list->next)
8586     if (((GtkTreeViewColumn *)list->data)->visible &&
8587         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8588       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8589
8590   /* Ensure we don't have a dangling pointer to a dead node */
8591   ensure_unprelighted (tree_view);
8592
8593   /* Cancel editting if we've started */
8594   gtk_tree_view_stop_editing (tree_view, TRUE);
8595
8596   /* If we have a node expanded/collapsed timeout, remove it */
8597   remove_expand_collapse_timeout (tree_view);
8598
8599   if (tree_view->priv->destroy_count_func)
8600     {
8601       gint child_count = 0;
8602       if (node->children)
8603         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8604       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8605     }
8606
8607   if (tree->root->count == 1)
8608     {
8609       if (tree_view->priv->tree == tree)
8610         tree_view->priv->tree = NULL;
8611
8612       _gtk_rbtree_remove (tree);
8613     }
8614   else
8615     {
8616       _gtk_rbtree_remove_node (tree, node);
8617     }
8618
8619   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8620     {
8621       gtk_tree_row_reference_free (tree_view->priv->top_row);
8622       tree_view->priv->top_row = NULL;
8623     }
8624
8625   install_scroll_sync_handler (tree_view);
8626
8627   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8628
8629   if (selection_changed)
8630     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8631 }
8632
8633 static void
8634 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8635                               GtkTreePath  *parent,
8636                               GtkTreeIter  *iter,
8637                               gint         *new_order,
8638                               gpointer      data)
8639 {
8640   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8641   GtkRBTree *tree;
8642   GtkRBNode *node;
8643   gint len;
8644
8645   len = gtk_tree_model_iter_n_children (model, iter);
8646
8647   if (len < 2)
8648     return;
8649
8650   gtk_tree_row_reference_reordered (G_OBJECT (data),
8651                                     parent,
8652                                     iter,
8653                                     new_order);
8654
8655   if (_gtk_tree_view_find_node (tree_view,
8656                                 parent,
8657                                 &tree,
8658                                 &node))
8659     return;
8660
8661   /* We need to special case the parent path */
8662   if (tree == NULL)
8663     tree = tree_view->priv->tree;
8664   else
8665     tree = node->children;
8666
8667   if (tree == NULL)
8668     return;
8669
8670   if (tree_view->priv->edited_column)
8671     gtk_tree_view_stop_editing (tree_view, TRUE);
8672
8673   /* we need to be unprelighted */
8674   ensure_unprelighted (tree_view);
8675
8676   /* clear the timeout */
8677   cancel_arrow_animation (tree_view);
8678   
8679   _gtk_rbtree_reorder (tree, new_order, len);
8680
8681   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8682
8683   gtk_tree_view_dy_to_top_row (tree_view);
8684 }
8685
8686
8687 /* Internal tree functions
8688  */
8689
8690
8691 static void
8692 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8693                                      GtkRBTree         *tree,
8694                                      GtkTreeViewColumn *column,
8695                                      gint              *x1,
8696                                      gint              *x2)
8697 {
8698   GtkTreeViewColumn *tmp_column = NULL;
8699   gint total_width;
8700   GList *list;
8701   gboolean rtl;
8702
8703   if (x1)
8704     *x1 = 0;
8705
8706   if (x2)
8707     *x2 = 0;
8708
8709   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8710
8711   total_width = 0;
8712   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8713        list;
8714        list = (rtl ? list->prev : list->next))
8715     {
8716       tmp_column = list->data;
8717
8718       if (tmp_column == column)
8719         break;
8720
8721       if (tmp_column->visible)
8722         total_width += tmp_column->width;
8723     }
8724
8725   if (tmp_column != column)
8726     {
8727       g_warning (G_STRLOC": passed-in column isn't in the tree");
8728       return;
8729     }
8730
8731   if (x1)
8732     *x1 = total_width;
8733
8734   if (x2)
8735     {
8736       if (column->visible)
8737         *x2 = total_width + column->width;
8738       else
8739         *x2 = total_width; /* width of 0 */
8740     }
8741 }
8742 static void
8743 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8744                                 GtkRBTree   *tree,
8745                                 gint        *x1,
8746                                 gint        *x2)
8747 {
8748   gint x_offset = 0;
8749   GList *list;
8750   GtkTreeViewColumn *tmp_column = NULL;
8751   gint total_width;
8752   gboolean indent_expanders;
8753   gboolean rtl;
8754
8755   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8756
8757   total_width = 0;
8758   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8759        list;
8760        list = (rtl ? list->prev : list->next))
8761     {
8762       tmp_column = list->data;
8763
8764       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8765         {
8766           if (rtl)
8767             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8768           else
8769             x_offset = total_width;
8770           break;
8771         }
8772
8773       if (tmp_column->visible)
8774         total_width += tmp_column->width;
8775     }
8776
8777   gtk_widget_style_get (GTK_WIDGET (tree_view),
8778                         "indent-expanders", &indent_expanders,
8779                         NULL);
8780
8781   if (indent_expanders)
8782     {
8783       if (rtl)
8784         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8785       else
8786         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8787     }
8788
8789   *x1 = x_offset;
8790   
8791   if (tmp_column && tmp_column->visible)
8792     /* +1 because x2 isn't included in the range. */
8793     *x2 = *x1 + tree_view->priv->expander_size + 1;
8794   else
8795     *x2 = *x1;
8796 }
8797
8798 static void
8799 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8800                           GtkRBTree   *tree,
8801                           GtkTreeIter *iter,
8802                           gint         depth,
8803                           gboolean     recurse)
8804 {
8805   GtkRBNode *temp = NULL;
8806   GtkTreePath *path = NULL;
8807   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8808
8809   do
8810     {
8811       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8812       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8813
8814       if (tree_view->priv->fixed_height > 0)
8815         {
8816           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8817             {
8818               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8819               _gtk_rbtree_node_mark_valid (tree, temp);
8820             }
8821         }
8822
8823       if (is_list)
8824         continue;
8825
8826       if (recurse)
8827         {
8828           GtkTreeIter child;
8829
8830           if (!path)
8831             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8832           else
8833             gtk_tree_path_next (path);
8834
8835           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8836             {
8837               gboolean expand;
8838
8839               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8840
8841               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8842                   && !expand)
8843                 {
8844                   temp->children = _gtk_rbtree_new ();
8845                   temp->children->parent_tree = tree;
8846                   temp->children->parent_node = temp;
8847                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8848                 }
8849             }
8850         }
8851
8852       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8853         {
8854           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8855             temp->flags ^= GTK_RBNODE_IS_PARENT;
8856         }
8857     }
8858   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8859
8860   if (path)
8861     gtk_tree_path_free (path);
8862 }
8863
8864 /* Make sure the node is visible vertically */
8865 static void
8866 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8867                                   GtkRBTree   *tree,
8868                                   GtkRBNode   *node)
8869 {
8870   gint node_dy, height;
8871   GtkTreePath *path = NULL;
8872
8873   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8874     return;
8875
8876   /* just return if the node is visible, avoiding a costly expose */
8877   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8878   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8879   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8880       && node_dy >= tree_view->priv->vadjustment->value
8881       && node_dy + height <= (tree_view->priv->vadjustment->value
8882                               + tree_view->priv->vadjustment->page_size))
8883     return;
8884
8885   path = _gtk_tree_view_find_path (tree_view, tree, node);
8886   if (path)
8887     {
8888       /* We process updates because we want to clear old selected items when we scroll.
8889        * if this is removed, we get a "selection streak" at the bottom. */
8890       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8891       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8892       gtk_tree_path_free (path);
8893     }
8894 }
8895
8896 static void
8897 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8898                                     GtkTreeViewColumn *column,
8899                                     gboolean           focus_to_cell)
8900 {
8901   GtkAllocation allocation;
8902   gint x, width;
8903
8904   if (column == NULL)
8905     return;
8906
8907   gtk_widget_get_allocation (column->button, &allocation);
8908   x = allocation.x;
8909   width = allocation.width;
8910
8911   if (width > tree_view->priv->hadjustment->page_size)
8912     {
8913       /* The column is larger than the horizontal page size.  If the
8914        * column has cells which can be focussed individually, then we make
8915        * sure the cell which gets focus is fully visible (if even the
8916        * focus cell is bigger than the page size, we make sure the
8917        * left-hand side of the cell is visible).
8918        *
8919        * If the column does not have those so-called special cells, we
8920        * make sure the left-hand side of the column is visible.
8921        */
8922
8923       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8924         {
8925           GtkTreePath *cursor_path;
8926           GdkRectangle background_area, cell_area, focus_area;
8927
8928           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8929
8930           gtk_tree_view_get_cell_area (tree_view,
8931                                        cursor_path, column, &cell_area);
8932           gtk_tree_view_get_background_area (tree_view,
8933                                              cursor_path, column,
8934                                              &background_area);
8935
8936           gtk_tree_path_free (cursor_path);
8937
8938           _gtk_tree_view_column_get_focus_area (column,
8939                                                 &background_area,
8940                                                 &cell_area,
8941                                                 &focus_area);
8942
8943           x = focus_area.x;
8944           width = focus_area.width;
8945
8946           if (width < tree_view->priv->hadjustment->page_size)
8947             {
8948               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8949                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8950                                           x + width - tree_view->priv->hadjustment->page_size);
8951               else if (tree_view->priv->hadjustment->value > x)
8952                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8953             }
8954         }
8955
8956       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8957     }
8958   else
8959     {
8960       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8961           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8962                                     x + width - tree_view->priv->hadjustment->page_size);
8963       else if (tree_view->priv->hadjustment->value > x)
8964         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8965   }
8966 }
8967
8968 /* This function could be more efficient.  I'll optimize it if profiling seems
8969  * to imply that it is important */
8970 GtkTreePath *
8971 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8972                           GtkRBTree   *tree,
8973                           GtkRBNode   *node)
8974 {
8975   GtkTreePath *path;
8976   GtkRBTree *tmp_tree;
8977   GtkRBNode *tmp_node, *last;
8978   gint count;
8979
8980   path = gtk_tree_path_new ();
8981
8982   g_return_val_if_fail (node != NULL, path);
8983   g_return_val_if_fail (node != tree->nil, path);
8984
8985   count = 1 + node->left->count;
8986
8987   last = node;
8988   tmp_node = node->parent;
8989   tmp_tree = tree;
8990   while (tmp_tree)
8991     {
8992       while (tmp_node != tmp_tree->nil)
8993         {
8994           if (tmp_node->right == last)
8995             count += 1 + tmp_node->left->count;
8996           last = tmp_node;
8997           tmp_node = tmp_node->parent;
8998         }
8999       gtk_tree_path_prepend_index (path, count - 1);
9000       last = tmp_tree->parent_node;
9001       tmp_tree = tmp_tree->parent_tree;
9002       if (last)
9003         {
9004           count = 1 + last->left->count;
9005           tmp_node = last->parent;
9006         }
9007     }
9008   return path;
9009 }
9010
9011 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9012  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9013  * both set to NULL.
9014  */
9015 gboolean
9016 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9017                           GtkTreePath  *path,
9018                           GtkRBTree   **tree,
9019                           GtkRBNode   **node)
9020 {
9021   GtkRBNode *tmpnode = NULL;
9022   GtkRBTree *tmptree = tree_view->priv->tree;
9023   gint *indices = gtk_tree_path_get_indices (path);
9024   gint depth = gtk_tree_path_get_depth (path);
9025   gint i = 0;
9026
9027   *node = NULL;
9028   *tree = NULL;
9029
9030   if (depth == 0 || tmptree == NULL)
9031     return FALSE;
9032   do
9033     {
9034       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9035       ++i;
9036       if (tmpnode == NULL)
9037         {
9038           *tree = NULL;
9039           *node = NULL;
9040           return FALSE;
9041         }
9042       if (i >= depth)
9043         {
9044           *tree = tmptree;
9045           *node = tmpnode;
9046           return FALSE;
9047         }
9048       *tree = tmptree;
9049       *node = tmpnode;
9050       tmptree = tmpnode->children;
9051       if (tmptree == NULL)
9052         return TRUE;
9053     }
9054   while (1);
9055 }
9056
9057 static gboolean
9058 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9059                                   GtkTreeViewColumn *column)
9060 {
9061   GList *list;
9062
9063   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9064     return FALSE;
9065
9066   if (tree_view->priv->expander_column != NULL)
9067     {
9068       if (tree_view->priv->expander_column == column)
9069         return TRUE;
9070       return FALSE;
9071     }
9072   else
9073     {
9074       for (list = tree_view->priv->columns;
9075            list;
9076            list = list->next)
9077         if (((GtkTreeViewColumn *)list->data)->visible)
9078           break;
9079       if (list && list->data == column)
9080         return TRUE;
9081     }
9082   return FALSE;
9083 }
9084
9085 static void
9086 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9087                                 guint           keyval,
9088                                 guint           modmask,
9089                                 gboolean        add_shifted_binding,
9090                                 GtkMovementStep step,
9091                                 gint            count)
9092 {
9093   
9094   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9095                                 "move-cursor", 2,
9096                                 G_TYPE_ENUM, step,
9097                                 G_TYPE_INT, count);
9098
9099   if (add_shifted_binding)
9100     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9101                                   "move-cursor", 2,
9102                                   G_TYPE_ENUM, step,
9103                                   G_TYPE_INT, count);
9104
9105   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9106    return;
9107
9108   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9109                                 "move-cursor", 2,
9110                                 G_TYPE_ENUM, step,
9111                                 G_TYPE_INT, count);
9112
9113   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9114                                 "move-cursor", 2,
9115                                 G_TYPE_ENUM, step,
9116                                 G_TYPE_INT, count);
9117 }
9118
9119 static gint
9120 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9121                                  GtkTreeIter  *iter,
9122                                  GtkRBTree    *tree,
9123                                  GtkRBNode    *node)
9124 {
9125   gint retval = FALSE;
9126   do
9127     {
9128       g_return_val_if_fail (node != NULL, FALSE);
9129
9130       if (node->children)
9131         {
9132           GtkTreeIter child;
9133           GtkRBTree *new_tree;
9134           GtkRBNode *new_node;
9135
9136           new_tree = node->children;
9137           new_node = new_tree->root;
9138
9139           while (new_node && new_node->left != new_tree->nil)
9140             new_node = new_node->left;
9141
9142           if (!gtk_tree_model_iter_children (model, &child, iter))
9143             return FALSE;
9144
9145           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9146         }
9147
9148       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9149         retval = TRUE;
9150       gtk_tree_model_unref_node (model, iter);
9151       node = _gtk_rbtree_next (tree, node);
9152     }
9153   while (gtk_tree_model_iter_next (model, iter));
9154
9155   return retval;
9156 }
9157
9158 static gint
9159 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9160                                               GtkRBTree   *tree)
9161 {
9162   GtkTreeIter iter;
9163   GtkTreePath *path;
9164   GtkRBNode *node;
9165   gint retval;
9166
9167   if (!tree)
9168     return FALSE;
9169
9170   node = tree->root;
9171   while (node && node->left != tree->nil)
9172     node = node->left;
9173
9174   g_return_val_if_fail (node != NULL, FALSE);
9175   path = _gtk_tree_view_find_path (tree_view, tree, node);
9176   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9177                            &iter, path);
9178   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9179   gtk_tree_path_free (path);
9180
9181   return retval;
9182 }
9183
9184 static void
9185 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9186                                     GtkTreeViewColumn *column)
9187 {
9188   GtkTreeViewColumn *left_column;
9189   GtkTreeViewColumn *cur_column = NULL;
9190   GtkTreeViewColumnReorder *reorder;
9191   gboolean rtl;
9192   GList *tmp_list;
9193   gint left;
9194
9195   /* We want to precalculate the motion list such that we know what column slots
9196    * are available.
9197    */
9198   left_column = NULL;
9199   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9200
9201   /* First, identify all possible drop spots */
9202   if (rtl)
9203     tmp_list = g_list_last (tree_view->priv->columns);
9204   else
9205     tmp_list = g_list_first (tree_view->priv->columns);
9206
9207   while (tmp_list)
9208     {
9209       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9210       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9211
9212       if (cur_column->visible == FALSE)
9213         continue;
9214
9215       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9216       if (left_column != column && cur_column != column &&
9217           tree_view->priv->column_drop_func &&
9218           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9219         {
9220           left_column = cur_column;
9221           continue;
9222         }
9223       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9224       reorder->left_column = left_column;
9225       left_column = reorder->right_column = cur_column;
9226
9227       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9228     }
9229
9230   /* Add the last one */
9231   if (tree_view->priv->column_drop_func == NULL ||
9232       ((left_column != column) &&
9233        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9234     {
9235       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9236       reorder->left_column = left_column;
9237       reorder->right_column = NULL;
9238       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9239     }
9240
9241   /* We quickly check to see if it even makes sense to reorder columns. */
9242   /* If there is nothing that can be moved, then we return */
9243
9244   if (tree_view->priv->column_drag_info == NULL)
9245     return;
9246
9247   /* We know there are always 2 slots possbile, as you can always return column. */
9248   /* If that's all there is, return */
9249   if (tree_view->priv->column_drag_info->next == NULL || 
9250       (tree_view->priv->column_drag_info->next->next == NULL &&
9251        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9252        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9253     {
9254       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9255         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9256       g_list_free (tree_view->priv->column_drag_info);
9257       tree_view->priv->column_drag_info = NULL;
9258       return;
9259     }
9260   /* We fill in the ranges for the columns, now that we've isolated them */
9261   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9262
9263   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9264     {
9265       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9266
9267       reorder->left_align = left;
9268       if (tmp_list->next != NULL)
9269         {
9270           GtkAllocation right_allocation, left_allocation;
9271
9272           g_assert (tmp_list->next->data);
9273
9274           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9275           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9276           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9277         }
9278       else
9279         {
9280           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9281                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9282         }
9283     }
9284 }
9285
9286 void
9287 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9288                                   GtkTreeViewColumn *column,
9289                                   GdkDevice         *device)
9290 {
9291   GdkEvent *send_event;
9292   GtkAllocation allocation;
9293   GtkAllocation button_allocation;
9294   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9295   GdkDisplay *display = gdk_screen_get_display (screen);
9296
9297   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9298   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9299
9300   gtk_tree_view_set_column_drag_info (tree_view, column);
9301
9302   if (tree_view->priv->column_drag_info == NULL)
9303     return;
9304
9305   if (tree_view->priv->drag_window == NULL)
9306     {
9307       GdkWindowAttr attributes;
9308       guint attributes_mask;
9309
9310       gtk_widget_get_allocation (column->button, &button_allocation);
9311
9312       attributes.window_type = GDK_WINDOW_CHILD;
9313       attributes.wclass = GDK_INPUT_OUTPUT;
9314       attributes.x = button_allocation.x;
9315       attributes.y = 0;
9316       attributes.width = button_allocation.width;
9317       attributes.height = button_allocation.height;
9318       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9319       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9320       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9321
9322       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9323                                                      &attributes,
9324                                                      attributes_mask);
9325       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9326     }
9327
9328   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9329   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9330
9331   gtk_grab_remove (column->button);
9332
9333   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9334   send_event->crossing.send_event = TRUE;
9335   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9336   send_event->crossing.subwindow = NULL;
9337   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9338   send_event->crossing.time = GDK_CURRENT_TIME;
9339   gdk_event_set_device (send_event, device);
9340
9341   gtk_propagate_event (column->button, send_event);
9342   gdk_event_free (send_event);
9343
9344   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9345   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9346   send_event->button.send_event = TRUE;
9347   send_event->button.time = GDK_CURRENT_TIME;
9348   send_event->button.x = -1;
9349   send_event->button.y = -1;
9350   send_event->button.axes = NULL;
9351   send_event->button.state = 0;
9352   send_event->button.button = 1;
9353   send_event->button.x_root = 0;
9354   send_event->button.y_root = 0;
9355   gdk_event_set_device (send_event, device);
9356
9357   gtk_propagate_event (column->button, send_event);
9358   gdk_event_free (send_event);
9359
9360   /* Kids, don't try this at home */
9361   g_object_ref (column->button);
9362   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9363   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9364   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9365   g_object_unref (column->button);
9366
9367   gtk_widget_get_allocation (column->button, &button_allocation);
9368   tree_view->priv->drag_column_x = button_allocation.x;
9369   allocation = button_allocation;
9370   allocation.x = 0;
9371   gtk_widget_size_allocate (column->button, &allocation);
9372   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9373
9374   tree_view->priv->drag_column = column;
9375   gdk_window_show (tree_view->priv->drag_window);
9376
9377   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9378   while (gtk_events_pending ())
9379     gtk_main_iteration ();
9380
9381   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9382   gdk_pointer_grab (tree_view->priv->drag_window,
9383                     FALSE,
9384                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9385                     NULL, NULL, GDK_CURRENT_TIME);
9386   gdk_keyboard_grab (tree_view->priv->drag_window,
9387                      FALSE,
9388                      GDK_CURRENT_TIME);
9389 }
9390
9391 static void
9392 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9393                                 GtkRBTree          *tree,
9394                                 GtkRBNode          *node)
9395 {
9396   GtkAllocation allocation;
9397   GdkRectangle rect;
9398
9399   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9400     return;
9401
9402   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9403   rect.x = 0;
9404   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9405
9406   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9407   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9408
9409   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9410 }
9411
9412 void
9413 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9414                                 GtkRBTree          *tree,
9415                                 GtkRBNode          *node,
9416                                 const GdkRectangle *clip_rect)
9417 {
9418   GtkAllocation allocation;
9419   GdkRectangle rect;
9420
9421   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9422     return;
9423
9424   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9425   rect.x = 0;
9426   rect.width = MAX (tree_view->priv->width, allocation.width);
9427
9428   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9429   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9430
9431   if (clip_rect)
9432     {
9433       GdkRectangle new_rect;
9434
9435       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9436
9437       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9438     }
9439   else
9440     {
9441       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9442     }
9443 }
9444
9445 static void
9446 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9447                                GtkTreePath        *path,
9448                                const GdkRectangle *clip_rect)
9449 {
9450   GtkRBTree *tree = NULL;
9451   GtkRBNode *node = NULL;
9452
9453   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9454
9455   if (tree)
9456     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9457 }
9458
9459 /* x and y are the mouse position
9460  */
9461 static void
9462 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9463                           cairo_t     *cr,
9464                           GtkRBTree   *tree,
9465                           GtkRBNode   *node,
9466                           /* in bin_window coordinates */
9467                           gint         x,
9468                           gint         y)
9469 {
9470   GdkRectangle area;
9471   GtkStateType state;
9472   GtkWidget *widget;
9473   gint x_offset = 0;
9474   gint x2;
9475   gint vertical_separator;
9476   gint expander_size;
9477   GtkExpanderStyle expander_style;
9478
9479   widget = GTK_WIDGET (tree_view);
9480
9481   gtk_widget_style_get (widget,
9482                         "vertical-separator", &vertical_separator,
9483                         NULL);
9484   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9485
9486   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9487     return;
9488
9489   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9490
9491   area.x = x_offset;
9492   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9493   area.width = expander_size + 2;
9494   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9495
9496   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9497     {
9498       state = GTK_STATE_INSENSITIVE;
9499     }
9500   else if (node == tree_view->priv->button_pressed_node)
9501     {
9502       if (x >= area.x && x <= (area.x + area.width) &&
9503           y >= area.y && y <= (area.y + area.height))
9504         state = GTK_STATE_ACTIVE;
9505       else
9506         state = GTK_STATE_NORMAL;
9507     }
9508   else
9509     {
9510       if (node == tree_view->priv->prelight_node &&
9511           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9512         state = GTK_STATE_PRELIGHT;
9513       else
9514         state = GTK_STATE_NORMAL;
9515     }
9516
9517   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9518     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9519   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9520     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9521   else if (node->children != NULL)
9522     expander_style = GTK_EXPANDER_EXPANDED;
9523   else
9524     expander_style = GTK_EXPANDER_COLLAPSED;
9525
9526   gtk_paint_expander (gtk_widget_get_style (widget),
9527                       cr,
9528                       state,
9529                       widget,
9530                       "treeview",
9531                       area.x + area.width / 2,
9532                       area.y + area.height / 2,
9533                       expander_style);
9534 }
9535
9536 static void
9537 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9538
9539 {
9540   GtkTreePath *cursor_path;
9541
9542   if ((tree_view->priv->tree == NULL) ||
9543       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9544     return;
9545
9546   cursor_path = NULL;
9547   if (tree_view->priv->cursor)
9548     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9549
9550   if (cursor_path == NULL)
9551     {
9552       /* Consult the selection before defaulting to the
9553        * first focusable element
9554        */
9555       GList *selected_rows;
9556       GtkTreeModel *model;
9557       GtkTreeSelection *selection;
9558
9559       selection = gtk_tree_view_get_selection (tree_view);
9560       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9561
9562       if (selected_rows)
9563         {
9564           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9565           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9566           g_list_free (selected_rows);
9567         }
9568       else
9569         {
9570           cursor_path = gtk_tree_path_new_first ();
9571           search_first_focusable_path (tree_view, &cursor_path,
9572                                        TRUE, NULL, NULL);
9573         }
9574
9575       gtk_tree_row_reference_free (tree_view->priv->cursor);
9576       tree_view->priv->cursor = NULL;
9577
9578       if (cursor_path)
9579         {
9580           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9581             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9582           else
9583             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9584         }
9585     }
9586
9587   if (cursor_path)
9588     {
9589       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9590
9591       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9592       gtk_tree_path_free (cursor_path);
9593
9594       if (tree_view->priv->focus_column == NULL)
9595         {
9596           GList *list;
9597           for (list = tree_view->priv->columns; list; list = list->next)
9598             {
9599               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9600                 {
9601                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9602                   break;
9603                 }
9604             }
9605         }
9606     }
9607 }
9608
9609 static void
9610 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9611                                    gint         count)
9612 {
9613   gint selection_count;
9614   GtkRBTree *cursor_tree = NULL;
9615   GtkRBNode *cursor_node = NULL;
9616   GtkRBTree *new_cursor_tree = NULL;
9617   GtkRBNode *new_cursor_node = NULL;
9618   GtkTreePath *cursor_path = NULL;
9619   gboolean grab_focus = TRUE;
9620   gboolean selectable;
9621
9622   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9623     return;
9624
9625   cursor_path = NULL;
9626   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9627     /* FIXME: we lost the cursor; should we get the first? */
9628     return;
9629
9630   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9631   _gtk_tree_view_find_node (tree_view, cursor_path,
9632                             &cursor_tree, &cursor_node);
9633
9634   if (cursor_tree == NULL)
9635     /* FIXME: we lost the cursor; should we get the first? */
9636     return;
9637
9638   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9639   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9640                                                       cursor_node,
9641                                                       cursor_path);
9642
9643   if (selection_count == 0
9644       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9645       && !tree_view->priv->ctrl_pressed
9646       && selectable)
9647     {
9648       /* Don't move the cursor, but just select the current node */
9649       new_cursor_tree = cursor_tree;
9650       new_cursor_node = cursor_node;
9651     }
9652   else
9653     {
9654       if (count == -1)
9655         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9656                                &new_cursor_tree, &new_cursor_node);
9657       else
9658         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9659                                &new_cursor_tree, &new_cursor_node);
9660     }
9661
9662   gtk_tree_path_free (cursor_path);
9663
9664   if (new_cursor_node)
9665     {
9666       cursor_path = _gtk_tree_view_find_path (tree_view,
9667                                               new_cursor_tree, new_cursor_node);
9668
9669       search_first_focusable_path (tree_view, &cursor_path,
9670                                    (count != -1),
9671                                    &new_cursor_tree,
9672                                    &new_cursor_node);
9673
9674       if (cursor_path)
9675         gtk_tree_path_free (cursor_path);
9676     }
9677
9678   /*
9679    * If the list has only one item and multi-selection is set then select
9680    * the row (if not yet selected).
9681    */
9682   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9683       new_cursor_node == NULL)
9684     {
9685       if (count == -1)
9686         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9687                                &new_cursor_tree, &new_cursor_node);
9688       else
9689         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9690                                &new_cursor_tree, &new_cursor_node);
9691
9692       if (new_cursor_node == NULL
9693           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9694         {
9695           new_cursor_node = cursor_node;
9696           new_cursor_tree = cursor_tree;
9697         }
9698       else
9699         {
9700           new_cursor_node = NULL;
9701         }
9702     }
9703
9704   if (new_cursor_node)
9705     {
9706       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9707       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9708       gtk_tree_path_free (cursor_path);
9709     }
9710   else
9711     {
9712       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9713
9714       if (!tree_view->priv->shift_pressed)
9715         {
9716           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9717                                           count < 0 ?
9718                                           GTK_DIR_UP : GTK_DIR_DOWN))
9719             {
9720               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9721
9722               if (toplevel)
9723                 gtk_widget_child_focus (toplevel,
9724                                         count < 0 ?
9725                                         GTK_DIR_TAB_BACKWARD :
9726                                         GTK_DIR_TAB_FORWARD);
9727
9728               grab_focus = FALSE;
9729             }
9730         }
9731       else
9732         {
9733           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9734         }
9735     }
9736
9737   if (grab_focus)
9738     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9739 }
9740
9741 static void
9742 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9743                                         gint         count)
9744 {
9745   GtkRBTree *cursor_tree = NULL;
9746   GtkRBNode *cursor_node = NULL;
9747   GtkTreePath *old_cursor_path = NULL;
9748   GtkTreePath *cursor_path = NULL;
9749   GtkRBTree *start_cursor_tree = NULL;
9750   GtkRBNode *start_cursor_node = NULL;
9751   gint y;
9752   gint window_y;
9753   gint vertical_separator;
9754
9755   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9756     return;
9757
9758   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9759     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9760   else
9761     /* This is sorta weird.  Focus in should give us a cursor */
9762     return;
9763
9764   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9765   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9766                             &cursor_tree, &cursor_node);
9767
9768   if (cursor_tree == NULL)
9769     {
9770       /* FIXME: we lost the cursor.  Should we try to get one? */
9771       gtk_tree_path_free (old_cursor_path);
9772       return;
9773     }
9774   g_return_if_fail (cursor_node != NULL);
9775
9776   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9777   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9778   y += tree_view->priv->cursor_offset;
9779   y += count * (int)tree_view->priv->vadjustment->page_increment;
9780   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9781
9782   if (y >= tree_view->priv->height)
9783     y = tree_view->priv->height - 1;
9784
9785   tree_view->priv->cursor_offset =
9786     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9787                              &cursor_tree, &cursor_node);
9788
9789   if (cursor_tree == NULL)
9790     {
9791       /* FIXME: we lost the cursor.  Should we try to get one? */
9792       gtk_tree_path_free (old_cursor_path);
9793       return;
9794     }
9795
9796   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9797     {
9798       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9799                              &cursor_tree, &cursor_node);
9800       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9801     }
9802
9803   y -= tree_view->priv->cursor_offset;
9804   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9805
9806   start_cursor_tree = cursor_tree;
9807   start_cursor_node = cursor_node;
9808
9809   if (! search_first_focusable_path (tree_view, &cursor_path,
9810                                      (count != -1),
9811                                      &cursor_tree, &cursor_node))
9812     {
9813       /* It looks like we reached the end of the view without finding
9814        * a focusable row.  We will step backwards to find the last
9815        * focusable row.
9816        */
9817       cursor_tree = start_cursor_tree;
9818       cursor_node = start_cursor_node;
9819       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9820
9821       search_first_focusable_path (tree_view, &cursor_path,
9822                                    (count == -1),
9823                                    &cursor_tree, &cursor_node);
9824     }
9825
9826   if (!cursor_path)
9827     goto cleanup;
9828
9829   /* update y */
9830   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9831
9832   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9833
9834   y -= window_y;
9835   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9836   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9837   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9838
9839   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9840     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9841
9842   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9843
9844 cleanup:
9845   gtk_tree_path_free (old_cursor_path);
9846   gtk_tree_path_free (cursor_path);
9847 }
9848
9849 static void
9850 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9851                                       gint         count)
9852 {
9853   GtkRBTree *cursor_tree = NULL;
9854   GtkRBNode *cursor_node = NULL;
9855   GtkTreePath *cursor_path = NULL;
9856   GtkTreeViewColumn *column;
9857   GtkTreeIter iter;
9858   GList *list;
9859   gboolean found_column = FALSE;
9860   gboolean rtl;
9861
9862   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9863
9864   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9865     return;
9866
9867   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9868     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9869   else
9870     return;
9871
9872   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9873   if (cursor_tree == NULL)
9874     return;
9875   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9876     {
9877       gtk_tree_path_free (cursor_path);
9878       return;
9879     }
9880   gtk_tree_path_free (cursor_path);
9881
9882   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9883   if (tree_view->priv->focus_column)
9884     {
9885       for (; list; list = (rtl ? list->prev : list->next))
9886         {
9887           if (list->data == tree_view->priv->focus_column)
9888             break;
9889         }
9890     }
9891
9892   while (list)
9893     {
9894       gboolean left, right;
9895
9896       column = list->data;
9897       if (column->visible == FALSE)
9898         goto loop_end;
9899
9900       gtk_tree_view_column_cell_set_cell_data (column,
9901                                                tree_view->priv->model,
9902                                                &iter,
9903                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9904                                                cursor_node->children?TRUE:FALSE);
9905
9906       if (rtl)
9907         {
9908           right = list->prev ? TRUE : FALSE;
9909           left = list->next ? TRUE : FALSE;
9910         }
9911       else
9912         {
9913           left = list->prev ? TRUE : FALSE;
9914           right = list->next ? TRUE : FALSE;
9915         }
9916
9917       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9918         {
9919           tree_view->priv->focus_column = column;
9920           found_column = TRUE;
9921           break;
9922         }
9923     loop_end:
9924       if (count == 1)
9925         list = rtl ? list->prev : list->next;
9926       else
9927         list = rtl ? list->next : list->prev;
9928     }
9929
9930   if (found_column)
9931     {
9932       if (!gtk_tree_view_has_special_cell (tree_view))
9933         _gtk_tree_view_queue_draw_node (tree_view,
9934                                         cursor_tree,
9935                                         cursor_node,
9936                                         NULL);
9937       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9938       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9939     }
9940   else
9941     {
9942       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9943     }
9944
9945   gtk_tree_view_clamp_column_visible (tree_view,
9946                                       tree_view->priv->focus_column, TRUE);
9947 }
9948
9949 static void
9950 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9951                                      gint         count)
9952 {
9953   GtkRBTree *cursor_tree;
9954   GtkRBNode *cursor_node;
9955   GtkTreePath *path;
9956   GtkTreePath *old_path;
9957
9958   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9959     return;
9960
9961   g_return_if_fail (tree_view->priv->tree != NULL);
9962
9963   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9964
9965   cursor_tree = tree_view->priv->tree;
9966   cursor_node = cursor_tree->root;
9967
9968   if (count == -1)
9969     {
9970       while (cursor_node && cursor_node->left != cursor_tree->nil)
9971         cursor_node = cursor_node->left;
9972
9973       /* Now go forward to find the first focusable row. */
9974       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9975       search_first_focusable_path (tree_view, &path,
9976                                    TRUE, &cursor_tree, &cursor_node);
9977     }
9978   else
9979     {
9980       do
9981         {
9982           while (cursor_node && cursor_node->right != cursor_tree->nil)
9983             cursor_node = cursor_node->right;
9984           if (cursor_node->children == NULL)
9985             break;
9986
9987           cursor_tree = cursor_node->children;
9988           cursor_node = cursor_tree->root;
9989         }
9990       while (1);
9991
9992       /* Now go backwards to find last focusable row. */
9993       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9994       search_first_focusable_path (tree_view, &path,
9995                                    FALSE, &cursor_tree, &cursor_node);
9996     }
9997
9998   if (!path)
9999     goto cleanup;
10000
10001   if (gtk_tree_path_compare (old_path, path))
10002     {
10003       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10004       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10005     }
10006   else
10007     {
10008       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10009     }
10010
10011 cleanup:
10012   gtk_tree_path_free (old_path);
10013   gtk_tree_path_free (path);
10014 }
10015
10016 static gboolean
10017 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10018 {
10019   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10020     return FALSE;
10021
10022   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10023     return FALSE;
10024
10025   gtk_tree_selection_select_all (tree_view->priv->selection);
10026
10027   return TRUE;
10028 }
10029
10030 static gboolean
10031 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10032 {
10033   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10034     return FALSE;
10035
10036   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10037     return FALSE;
10038
10039   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10040
10041   return TRUE;
10042 }
10043
10044 static gboolean
10045 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10046                                       gboolean     start_editing)
10047 {
10048   GtkRBTree *new_tree = NULL;
10049   GtkRBNode *new_node = NULL;
10050   GtkRBTree *cursor_tree = NULL;
10051   GtkRBNode *cursor_node = NULL;
10052   GtkTreePath *cursor_path = NULL;
10053   GtkTreeSelectMode mode = 0;
10054
10055   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10056     return FALSE;
10057
10058   if (tree_view->priv->cursor)
10059     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10060
10061   if (cursor_path == NULL)
10062     return FALSE;
10063
10064   _gtk_tree_view_find_node (tree_view, cursor_path,
10065                             &cursor_tree, &cursor_node);
10066
10067   if (cursor_tree == NULL)
10068     {
10069       gtk_tree_path_free (cursor_path);
10070       return FALSE;
10071     }
10072
10073   if (!tree_view->priv->shift_pressed && start_editing &&
10074       tree_view->priv->focus_column)
10075     {
10076       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10077         {
10078           gtk_tree_path_free (cursor_path);
10079           return TRUE;
10080         }
10081     }
10082
10083   if (tree_view->priv->ctrl_pressed)
10084     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10085   if (tree_view->priv->shift_pressed)
10086     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10087
10088   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10089                                             cursor_node,
10090                                             cursor_tree,
10091                                             cursor_path,
10092                                             mode,
10093                                             FALSE);
10094
10095   /* We bail out if the original (tree, node) don't exist anymore after
10096    * handling the selection-changed callback.  We do return TRUE because
10097    * the key press has been handled at this point.
10098    */
10099   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10100
10101   if (cursor_tree != new_tree || cursor_node != new_node)
10102     return FALSE;
10103
10104   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10105
10106   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10107   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10108
10109   if (!tree_view->priv->shift_pressed)
10110     gtk_tree_view_row_activated (tree_view, cursor_path,
10111                                  tree_view->priv->focus_column);
10112     
10113   gtk_tree_path_free (cursor_path);
10114
10115   return TRUE;
10116 }
10117
10118 static gboolean
10119 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10120 {
10121   GtkRBTree *new_tree = NULL;
10122   GtkRBNode *new_node = NULL;
10123   GtkRBTree *cursor_tree = NULL;
10124   GtkRBNode *cursor_node = NULL;
10125   GtkTreePath *cursor_path = NULL;
10126
10127   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10128     return FALSE;
10129
10130   cursor_path = NULL;
10131   if (tree_view->priv->cursor)
10132     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10133
10134   if (cursor_path == NULL)
10135     return FALSE;
10136
10137   _gtk_tree_view_find_node (tree_view, cursor_path,
10138                             &cursor_tree, &cursor_node);
10139   if (cursor_tree == NULL)
10140     {
10141       gtk_tree_path_free (cursor_path);
10142       return FALSE;
10143     }
10144
10145   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10146                                             cursor_node,
10147                                             cursor_tree,
10148                                             cursor_path,
10149                                             GTK_TREE_SELECT_MODE_TOGGLE,
10150                                             FALSE);
10151
10152   /* We bail out if the original (tree, node) don't exist anymore after
10153    * handling the selection-changed callback.  We do return TRUE because
10154    * the key press has been handled at this point.
10155    */
10156   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10157
10158   if (cursor_tree != new_tree || cursor_node != new_node)
10159     return FALSE;
10160
10161   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10162
10163   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10164   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10165   gtk_tree_path_free (cursor_path);
10166
10167   return TRUE;
10168 }
10169
10170 static gboolean
10171 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10172                                                gboolean     logical,
10173                                                gboolean     expand,
10174                                                gboolean     open_all)
10175 {
10176   GtkTreePath *cursor_path = NULL;
10177   GtkRBTree *tree;
10178   GtkRBNode *node;
10179
10180   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10181     return FALSE;
10182
10183   cursor_path = NULL;
10184   if (tree_view->priv->cursor)
10185     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10186
10187   if (cursor_path == NULL)
10188     return FALSE;
10189
10190   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10191     return FALSE;
10192
10193   /* Don't handle the event if we aren't an expander */
10194   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10195     return FALSE;
10196
10197   if (!logical
10198       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10199     expand = !expand;
10200
10201   if (expand)
10202     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10203   else
10204     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10205
10206   gtk_tree_path_free (cursor_path);
10207
10208   return TRUE;
10209 }
10210
10211 static gboolean
10212 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10213 {
10214   GtkRBTree *cursor_tree = NULL;
10215   GtkRBNode *cursor_node = NULL;
10216   GtkTreePath *cursor_path = NULL;
10217   GdkModifierType state;
10218
10219   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10220     goto out;
10221
10222   cursor_path = NULL;
10223   if (tree_view->priv->cursor)
10224     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10225
10226   if (cursor_path == NULL)
10227     goto out;
10228
10229   _gtk_tree_view_find_node (tree_view, cursor_path,
10230                             &cursor_tree, &cursor_node);
10231   if (cursor_tree == NULL)
10232     {
10233       gtk_tree_path_free (cursor_path);
10234       goto out;
10235     }
10236
10237   if (cursor_tree->parent_node)
10238     {
10239       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10240       cursor_node = cursor_tree->parent_node;
10241       cursor_tree = cursor_tree->parent_tree;
10242
10243       gtk_tree_path_up (cursor_path);
10244
10245       if (gtk_get_current_event_state (&state))
10246         {
10247           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10248             tree_view->priv->ctrl_pressed = TRUE;
10249         }
10250
10251       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10252       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10253
10254       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10255       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10256       gtk_tree_path_free (cursor_path);
10257
10258       tree_view->priv->ctrl_pressed = FALSE;
10259
10260       return TRUE;
10261     }
10262
10263  out:
10264
10265   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10266   return FALSE;
10267 }
10268
10269 static gboolean
10270 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10271 {
10272   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10273   tree_view->priv->typeselect_flush_timeout = 0;
10274
10275   return FALSE;
10276 }
10277
10278 /* Cut and paste from gtkwindow.c */
10279 static void
10280 send_focus_change (GtkWidget *widget,
10281                    GdkDevice *device,
10282                    gboolean   in)
10283 {
10284   GdkDeviceManager *device_manager;
10285   GList *devices, *d;
10286
10287   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10288   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10289   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10290   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10291
10292   for (d = devices; d; d = d->next)
10293     {
10294       GdkDevice *dev = d->data;
10295       GdkEvent *fevent;
10296       GdkWindow *window;
10297
10298       if (dev->source != GDK_SOURCE_KEYBOARD)
10299         continue;
10300
10301       window = gtk_widget_get_window (widget);
10302
10303       /* Skip non-master keyboards that haven't
10304        * selected for events from this window
10305        */
10306       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10307           !gdk_window_get_device_events (window, dev))
10308         continue;
10309
10310       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10311
10312       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10313       fevent->focus_change.window = g_object_ref (window);
10314       fevent->focus_change.in = in;
10315       gdk_event_set_device (fevent, device);
10316
10317       gtk_widget_send_focus_change (widget, fevent);
10318
10319       gdk_event_free (fevent);
10320     }
10321 }
10322
10323 static void
10324 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10325 {
10326   GtkWidget *frame, *vbox, *toplevel;
10327   GdkScreen *screen;
10328
10329   if (tree_view->priv->search_custom_entry_set)
10330     return;
10331
10332   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10333   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10334
10335    if (tree_view->priv->search_window != NULL)
10336      {
10337        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10338          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10339                                       GTK_WINDOW (tree_view->priv->search_window));
10340        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10341          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10342                                          GTK_WINDOW (tree_view->priv->search_window));
10343
10344        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10345
10346        return;
10347      }
10348    
10349   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10350   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10351
10352   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10353     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10354                                  GTK_WINDOW (tree_view->priv->search_window));
10355
10356   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10357                             GDK_WINDOW_TYPE_HINT_UTILITY);
10358   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10359   g_signal_connect (tree_view->priv->search_window, "delete-event",
10360                     G_CALLBACK (gtk_tree_view_search_delete_event),
10361                     tree_view);
10362   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10363                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10364                     tree_view);
10365   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10366                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10367                     tree_view);
10368   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10369                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10370                     tree_view);
10371
10372   frame = gtk_frame_new (NULL);
10373   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10374   gtk_widget_show (frame);
10375   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10376
10377   vbox = gtk_vbox_new (FALSE, 0);
10378   gtk_widget_show (vbox);
10379   gtk_container_add (GTK_CONTAINER (frame), vbox);
10380   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10381
10382   /* add entry */
10383   tree_view->priv->search_entry = gtk_entry_new ();
10384   gtk_widget_show (tree_view->priv->search_entry);
10385   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10386                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10387                     tree_view);
10388   g_signal_connect (tree_view->priv->search_entry,
10389                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10390                     tree_view);
10391   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10392                     "preedit-changed",
10393                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10394                     tree_view);
10395   gtk_container_add (GTK_CONTAINER (vbox),
10396                      tree_view->priv->search_entry);
10397
10398   gtk_widget_realize (tree_view->priv->search_entry);
10399 }
10400
10401 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10402  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10403  */
10404 static gboolean
10405 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10406                                              GdkDevice   *device,
10407                                              gboolean     keybinding)
10408 {
10409   /* We only start interactive search if we have focus or the columns
10410    * have focus.  If one of our children have focus, we don't want to
10411    * start the search.
10412    */
10413   GList *list;
10414   gboolean found_focus = FALSE;
10415   GtkWidgetClass *entry_parent_class;
10416   
10417   if (!tree_view->priv->enable_search && !keybinding)
10418     return FALSE;
10419
10420   if (tree_view->priv->search_custom_entry_set)
10421     return FALSE;
10422
10423   if (tree_view->priv->search_window != NULL &&
10424       gtk_widget_get_visible (tree_view->priv->search_window))
10425     return TRUE;
10426
10427   for (list = tree_view->priv->columns; list; list = list->next)
10428     {
10429       GtkTreeViewColumn *column;
10430
10431       column = list->data;
10432       if (! column->visible)
10433         continue;
10434
10435       if (gtk_widget_has_focus (column->button))
10436         {
10437           found_focus = TRUE;
10438           break;
10439         }
10440     }
10441   
10442   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10443     found_focus = TRUE;
10444
10445   if (!found_focus)
10446     return FALSE;
10447
10448   if (tree_view->priv->search_column < 0)
10449     return FALSE;
10450
10451   gtk_tree_view_ensure_interactive_directory (tree_view);
10452
10453   if (keybinding)
10454     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10455
10456   /* done, show it */
10457   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10458   gtk_widget_show (tree_view->priv->search_window);
10459   if (tree_view->priv->search_entry_changed_id == 0)
10460     {
10461       tree_view->priv->search_entry_changed_id =
10462         g_signal_connect (tree_view->priv->search_entry, "changed",
10463                           G_CALLBACK (gtk_tree_view_search_init),
10464                           tree_view);
10465     }
10466
10467   tree_view->priv->typeselect_flush_timeout =
10468     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10469                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10470                    tree_view);
10471
10472   /* Grab focus will select all the text.  We don't want that to happen, so we
10473    * call the parent instance and bypass the selection change.  This is probably
10474    * really non-kosher. */
10475   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10476   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10477
10478   /* send focus-in event */
10479   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10480
10481   /* search first matching iter */
10482   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10483
10484   return TRUE;
10485 }
10486
10487 static gboolean
10488 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10489 {
10490   return gtk_tree_view_real_start_interactive_search (tree_view,
10491                                                       gtk_get_current_event_device (),
10492                                                       TRUE);
10493 }
10494
10495 /* this function returns the new width of the column being resized given
10496  * the column and x position of the cursor; the x cursor position is passed
10497  * in as a pointer and automagicly corrected if it's beyond min/max limits
10498  */
10499 static gint
10500 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10501                                 gint       i,
10502                                 gint      *x)
10503 {
10504   GtkAllocation allocation;
10505   GtkTreeViewColumn *column;
10506   GtkRequisition button_req;
10507   gint width;
10508   gboolean rtl;
10509
10510   /* first translate the x position from widget->window
10511    * to clist->clist_window
10512    */
10513   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10514   column = g_list_nth (tree_view->priv->columns, i)->data;
10515   gtk_widget_get_allocation (column->button, &allocation);
10516   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10517
10518   /* Clamp down the value */
10519   if (column->min_width == -1)
10520     {
10521       gtk_widget_get_preferred_size (column->button, &button_req, NULL);
10522       width = MAX (button_req.width, width);
10523     }
10524   else
10525     width = MAX (column->min_width,
10526                  width);
10527   if (column->max_width != -1)
10528     width = MIN (width, column->max_width);
10529
10530   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10531
10532   return width;
10533 }
10534
10535
10536 /* FIXME this adjust_allocation is a big cut-and-paste from
10537  * GtkCList, needs to be some "official" way to do this
10538  * factored out.
10539  */
10540 typedef struct
10541 {
10542   GdkWindow *window;
10543   int dx;
10544   int dy;
10545 } ScrollData;
10546
10547 /* The window to which widget->window is relative */
10548 #define ALLOCATION_WINDOW(widget)               \
10549    (!gtk_widget_get_has_window (widget) ?                   \
10550     gtk_widget_get_window (widget) :                        \
10551     gdk_window_get_parent (gtk_widget_get_window (widget)))
10552
10553 static void
10554 adjust_allocation_recurse (GtkWidget *widget,
10555                            gpointer   data)
10556 {
10557   GtkAllocation allocation;
10558   ScrollData *scroll_data = data;
10559
10560   /* Need to really size allocate instead of just poking
10561    * into widget->allocation if the widget is not realized.
10562    * FIXME someone figure out why this was.
10563    */
10564   gtk_widget_get_allocation (widget, &allocation);
10565   if (!gtk_widget_get_realized (widget))
10566     {
10567       if (gtk_widget_get_visible (widget))
10568         {
10569           GdkRectangle tmp_rectangle = allocation;
10570           tmp_rectangle.x += scroll_data->dx;
10571           tmp_rectangle.y += scroll_data->dy;
10572           
10573           gtk_widget_size_allocate (widget, &tmp_rectangle);
10574         }
10575     }
10576   else
10577     {
10578       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10579         {
10580           allocation.x += scroll_data->dx;
10581           allocation.y += scroll_data->dy;
10582           gtk_widget_set_allocation (widget, &allocation);
10583
10584           if (GTK_IS_CONTAINER (widget))
10585             gtk_container_forall (GTK_CONTAINER (widget),
10586                                   adjust_allocation_recurse,
10587                                   data);
10588         }
10589     }
10590 }
10591
10592 static void
10593 adjust_allocation (GtkWidget *widget,
10594                    int        dx,
10595                    int        dy)
10596 {
10597   ScrollData scroll_data;
10598
10599   if (gtk_widget_get_realized (widget))
10600     scroll_data.window = ALLOCATION_WINDOW (widget);
10601   else
10602     scroll_data.window = NULL;
10603     
10604   scroll_data.dx = dx;
10605   scroll_data.dy = dy;
10606   
10607   adjust_allocation_recurse (widget, &scroll_data);
10608 }
10609
10610 /* Callbacks */
10611 static void
10612 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10613                                   GtkTreeView   *tree_view)
10614 {
10615   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10616     {
10617       gint dy;
10618         
10619       gdk_window_move (tree_view->priv->bin_window,
10620                        - tree_view->priv->hadjustment->value,
10621                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10622       gdk_window_move (tree_view->priv->header_window,
10623                        - tree_view->priv->hadjustment->value,
10624                        0);
10625       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10626       if (dy)
10627         {
10628           update_prelight (tree_view,
10629                            tree_view->priv->event_last_x,
10630                            tree_view->priv->event_last_y - dy);
10631
10632           if (tree_view->priv->edited_column &&
10633               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10634             {
10635               GList *list;
10636               GtkWidget *widget;
10637               GtkTreeViewChild *child = NULL;
10638
10639               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10640               adjust_allocation (widget, 0, dy); 
10641               
10642               for (list = tree_view->priv->children; list; list = list->next)
10643                 {
10644                   child = (GtkTreeViewChild *)list->data;
10645                   if (child->widget == widget)
10646                     {
10647                       child->y += dy;
10648                       break;
10649                     }
10650                 }
10651             }
10652         }
10653       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10654
10655       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10656         {
10657           /* update our dy and top_row */
10658           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10659
10660           if (!tree_view->priv->in_top_row_to_dy)
10661             gtk_tree_view_dy_to_top_row (tree_view);
10662         }
10663
10664       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10665       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
10666     }
10667 }
10668
10669 \f
10670
10671 /* Public methods
10672  */
10673
10674 /**
10675  * gtk_tree_view_new:
10676  *
10677  * Creates a new #GtkTreeView widget.
10678  *
10679  * Return value: A newly created #GtkTreeView widget.
10680  **/
10681 GtkWidget *
10682 gtk_tree_view_new (void)
10683 {
10684   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10685 }
10686
10687 /**
10688  * gtk_tree_view_new_with_model:
10689  * @model: the model.
10690  *
10691  * Creates a new #GtkTreeView widget with the model initialized to @model.
10692  *
10693  * Return value: A newly created #GtkTreeView widget.
10694  **/
10695 GtkWidget *
10696 gtk_tree_view_new_with_model (GtkTreeModel *model)
10697 {
10698   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10699 }
10700
10701 /* Public Accessors
10702  */
10703
10704 /**
10705  * gtk_tree_view_get_model:
10706  * @tree_view: a #GtkTreeView
10707  *
10708  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10709  * model is unset.
10710  *
10711  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10712  **/
10713 GtkTreeModel *
10714 gtk_tree_view_get_model (GtkTreeView *tree_view)
10715 {
10716   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10717
10718   return tree_view->priv->model;
10719 }
10720
10721 /**
10722  * gtk_tree_view_set_model:
10723  * @tree_view: A #GtkTreeNode.
10724  * @model: (allow-none): The model.
10725  *
10726  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10727  * set, it will remove it before setting the new model.  If @model is %NULL,
10728  * then it will unset the old model.
10729  **/
10730 void
10731 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10732                          GtkTreeModel *model)
10733 {
10734   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10735   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10736
10737   if (model == tree_view->priv->model)
10738     return;
10739
10740   if (tree_view->priv->scroll_to_path)
10741     {
10742       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10743       tree_view->priv->scroll_to_path = NULL;
10744     }
10745
10746   if (tree_view->priv->model)
10747     {
10748       GList *tmplist = tree_view->priv->columns;
10749
10750       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10751       gtk_tree_view_stop_editing (tree_view, TRUE);
10752
10753       remove_expand_collapse_timeout (tree_view);
10754
10755       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10756                                             gtk_tree_view_row_changed,
10757                                             tree_view);
10758       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10759                                             gtk_tree_view_row_inserted,
10760                                             tree_view);
10761       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10762                                             gtk_tree_view_row_has_child_toggled,
10763                                             tree_view);
10764       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10765                                             gtk_tree_view_row_deleted,
10766                                             tree_view);
10767       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10768                                             gtk_tree_view_rows_reordered,
10769                                             tree_view);
10770
10771       for (; tmplist; tmplist = tmplist->next)
10772         _gtk_tree_view_column_unset_model (tmplist->data,
10773                                            tree_view->priv->model);
10774
10775       if (tree_view->priv->tree)
10776         gtk_tree_view_free_rbtree (tree_view);
10777
10778       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10779       tree_view->priv->drag_dest_row = NULL;
10780       gtk_tree_row_reference_free (tree_view->priv->cursor);
10781       tree_view->priv->cursor = NULL;
10782       gtk_tree_row_reference_free (tree_view->priv->anchor);
10783       tree_view->priv->anchor = NULL;
10784       gtk_tree_row_reference_free (tree_view->priv->top_row);
10785       tree_view->priv->top_row = NULL;
10786       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10787       tree_view->priv->scroll_to_path = NULL;
10788
10789       tree_view->priv->scroll_to_column = NULL;
10790
10791       g_object_unref (tree_view->priv->model);
10792
10793       tree_view->priv->search_column = -1;
10794       tree_view->priv->fixed_height_check = 0;
10795       tree_view->priv->fixed_height = -1;
10796       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10797       tree_view->priv->last_button_x = -1;
10798       tree_view->priv->last_button_y = -1;
10799     }
10800
10801   tree_view->priv->model = model;
10802
10803   if (tree_view->priv->model)
10804     {
10805       gint i;
10806       GtkTreePath *path;
10807       GtkTreeIter iter;
10808       GtkTreeModelFlags flags;
10809
10810       if (tree_view->priv->search_column == -1)
10811         {
10812           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10813             {
10814               GType type = gtk_tree_model_get_column_type (model, i);
10815
10816               if (g_value_type_transformable (type, G_TYPE_STRING))
10817                 {
10818                   tree_view->priv->search_column = i;
10819                   break;
10820                 }
10821             }
10822         }
10823
10824       g_object_ref (tree_view->priv->model);
10825       g_signal_connect (tree_view->priv->model,
10826                         "row-changed",
10827                         G_CALLBACK (gtk_tree_view_row_changed),
10828                         tree_view);
10829       g_signal_connect (tree_view->priv->model,
10830                         "row-inserted",
10831                         G_CALLBACK (gtk_tree_view_row_inserted),
10832                         tree_view);
10833       g_signal_connect (tree_view->priv->model,
10834                         "row-has-child-toggled",
10835                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10836                         tree_view);
10837       g_signal_connect (tree_view->priv->model,
10838                         "row-deleted",
10839                         G_CALLBACK (gtk_tree_view_row_deleted),
10840                         tree_view);
10841       g_signal_connect (tree_view->priv->model,
10842                         "rows-reordered",
10843                         G_CALLBACK (gtk_tree_view_rows_reordered),
10844                         tree_view);
10845
10846       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10847       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10848         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10849       else
10850         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10851
10852       path = gtk_tree_path_new_first ();
10853       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10854         {
10855           tree_view->priv->tree = _gtk_rbtree_new ();
10856           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10857         }
10858       gtk_tree_path_free (path);
10859
10860       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10861       install_presize_handler (tree_view);
10862     }
10863
10864   g_object_notify (G_OBJECT (tree_view), "model");
10865
10866   if (tree_view->priv->selection)
10867   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10868
10869   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10870     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10871 }
10872
10873 /**
10874  * gtk_tree_view_get_selection:
10875  * @tree_view: A #GtkTreeView.
10876  *
10877  * Gets the #GtkTreeSelection associated with @tree_view.
10878  *
10879  * Return value: (transfer none): A #GtkTreeSelection object.
10880  **/
10881 GtkTreeSelection *
10882 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10883 {
10884   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10885
10886   return tree_view->priv->selection;
10887 }
10888
10889 /**
10890  * gtk_tree_view_get_hadjustment:
10891  * @tree_view: A #GtkTreeView
10892  *
10893  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10894  *
10895  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10896  *     if none is currently being used.
10897  **/
10898 GtkAdjustment *
10899 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10900 {
10901   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10902
10903   if (tree_view->priv->hadjustment == NULL)
10904     gtk_tree_view_set_hadjustment (tree_view, NULL);
10905
10906   return tree_view->priv->hadjustment;
10907 }
10908
10909 /**
10910  * gtk_tree_view_set_hadjustment:
10911  * @tree_view: A #GtkTreeView
10912  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10913  *
10914  * Sets the #GtkAdjustment for the current horizontal aspect.
10915  **/
10916 void
10917 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10918                                GtkAdjustment *adjustment)
10919 {
10920   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10921
10922   gtk_tree_view_set_adjustments (tree_view,
10923                                  adjustment,
10924                                  tree_view->priv->vadjustment);
10925
10926   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10927 }
10928
10929 /**
10930  * gtk_tree_view_get_vadjustment:
10931  * @tree_view: A #GtkTreeView
10932  *
10933  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10934  *
10935  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10936  *     if none is currently being used.
10937  **/
10938 GtkAdjustment *
10939 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10940 {
10941   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10942
10943   if (tree_view->priv->vadjustment == NULL)
10944     gtk_tree_view_set_vadjustment (tree_view, NULL);
10945
10946   return tree_view->priv->vadjustment;
10947 }
10948
10949 /**
10950  * gtk_tree_view_set_vadjustment:
10951  * @tree_view: A #GtkTreeView
10952  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10953  *
10954  * Sets the #GtkAdjustment for the current vertical aspect.
10955  **/
10956 void
10957 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10958                                GtkAdjustment *adjustment)
10959 {
10960   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10961
10962   gtk_tree_view_set_adjustments (tree_view,
10963                                  tree_view->priv->hadjustment,
10964                                  adjustment);
10965
10966   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10967 }
10968
10969 /* Column and header operations */
10970
10971 /**
10972  * gtk_tree_view_get_headers_visible:
10973  * @tree_view: A #GtkTreeView.
10974  *
10975  * Returns %TRUE if the headers on the @tree_view are visible.
10976  *
10977  * Return value: Whether the headers are visible or not.
10978  **/
10979 gboolean
10980 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10981 {
10982   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10983
10984   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10985 }
10986
10987 /**
10988  * gtk_tree_view_set_headers_visible:
10989  * @tree_view: A #GtkTreeView.
10990  * @headers_visible: %TRUE if the headers are visible
10991  *
10992  * Sets the visibility state of the headers.
10993  **/
10994 void
10995 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10996                                    gboolean     headers_visible)
10997 {
10998   gint x, y;
10999   GList *list;
11000   GtkTreeViewColumn *column;
11001   GtkAllocation allocation;
11002
11003   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11004
11005   headers_visible = !! headers_visible;
11006
11007   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11008     return;
11009
11010   if (headers_visible)
11011     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11012   else
11013     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11014
11015   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11016     {
11017       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11018       if (headers_visible)
11019         {
11020           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11021           gdk_window_move_resize (tree_view->priv->bin_window,
11022                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11023                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11024
11025           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11026             gtk_tree_view_map_buttons (tree_view);
11027         }
11028       else
11029         {
11030           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11031
11032           for (list = tree_view->priv->columns; list; list = list->next)
11033             {
11034               column = list->data;
11035               gtk_widget_unmap (column->button);
11036             }
11037           gdk_window_hide (tree_view->priv->header_window);
11038         }
11039     }
11040
11041   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11042   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11043   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11044   tree_view->priv->vadjustment->lower = 0;
11045   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11046   gtk_adjustment_changed (tree_view->priv->vadjustment);
11047
11048   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11049
11050   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11051 }
11052
11053 /**
11054  * gtk_tree_view_columns_autosize:
11055  * @tree_view: A #GtkTreeView.
11056  *
11057  * Resizes all columns to their optimal width. Only works after the
11058  * treeview has been realized.
11059  **/
11060 void
11061 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11062 {
11063   gboolean dirty = FALSE;
11064   GList *list;
11065   GtkTreeViewColumn *column;
11066
11067   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11068
11069   for (list = tree_view->priv->columns; list; list = list->next)
11070     {
11071       column = list->data;
11072       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11073         continue;
11074       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11075       dirty = TRUE;
11076     }
11077
11078   if (dirty)
11079     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11080 }
11081
11082 /**
11083  * gtk_tree_view_set_headers_clickable:
11084  * @tree_view: A #GtkTreeView.
11085  * @setting: %TRUE if the columns are clickable.
11086  *
11087  * Allow the column title buttons to be clicked.
11088  **/
11089 void
11090 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11091                                      gboolean   setting)
11092 {
11093   GList *list;
11094
11095   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11096
11097   for (list = tree_view->priv->columns; list; list = list->next)
11098     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11099
11100   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11101 }
11102
11103
11104 /**
11105  * gtk_tree_view_get_headers_clickable:
11106  * @tree_view: A #GtkTreeView.
11107  *
11108  * Returns whether all header columns are clickable.
11109  *
11110  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11111  *
11112  * Since: 2.10
11113  **/
11114 gboolean 
11115 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11116 {
11117   GList *list;
11118   
11119   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11120
11121   for (list = tree_view->priv->columns; list; list = list->next)
11122     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11123       return FALSE;
11124
11125   return TRUE;
11126 }
11127
11128 /**
11129  * gtk_tree_view_set_rules_hint
11130  * @tree_view: a #GtkTreeView
11131  * @setting: %TRUE if the tree requires reading across rows
11132  *
11133  * This function tells GTK+ that the user interface for your
11134  * application requires users to read across tree rows and associate
11135  * cells with one another. By default, GTK+ will then render the tree
11136  * with alternating row colors. Do <emphasis>not</emphasis> use it
11137  * just because you prefer the appearance of the ruled tree; that's a
11138  * question for the theme. Some themes will draw tree rows in
11139  * alternating colors even when rules are turned off, and users who
11140  * prefer that appearance all the time can choose those themes. You
11141  * should call this function only as a <emphasis>semantic</emphasis>
11142  * hint to the theme engine that your tree makes alternating colors
11143  * useful from a functional standpoint (since it has lots of columns,
11144  * generally).
11145  *
11146  **/
11147 void
11148 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11149                               gboolean      setting)
11150 {
11151   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11152
11153   setting = setting != FALSE;
11154
11155   if (tree_view->priv->has_rules != setting)
11156     {
11157       tree_view->priv->has_rules = setting;
11158       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11159     }
11160
11161   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11162 }
11163
11164 /**
11165  * gtk_tree_view_get_rules_hint
11166  * @tree_view: a #GtkTreeView
11167  *
11168  * Gets the setting set by gtk_tree_view_set_rules_hint().
11169  *
11170  * Return value: %TRUE if rules are useful for the user of this tree
11171  **/
11172 gboolean
11173 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11174 {
11175   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11176
11177   return tree_view->priv->has_rules;
11178 }
11179
11180 /* Public Column functions
11181  */
11182
11183 /**
11184  * gtk_tree_view_append_column:
11185  * @tree_view: A #GtkTreeView.
11186  * @column: The #GtkTreeViewColumn to add.
11187  *
11188  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11189  * mode enabled, then @column must have its "sizing" property set to be
11190  * GTK_TREE_VIEW_COLUMN_FIXED.
11191  *
11192  * Return value: The number of columns in @tree_view after appending.
11193  **/
11194 gint
11195 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11196                              GtkTreeViewColumn *column)
11197 {
11198   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11199   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11200   g_return_val_if_fail (column->tree_view == NULL, -1);
11201
11202   return gtk_tree_view_insert_column (tree_view, column, -1);
11203 }
11204
11205
11206 /**
11207  * gtk_tree_view_remove_column:
11208  * @tree_view: A #GtkTreeView.
11209  * @column: The #GtkTreeViewColumn to remove.
11210  *
11211  * Removes @column from @tree_view.
11212  *
11213  * Return value: The number of columns in @tree_view after removing.
11214  **/
11215 gint
11216 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11217                              GtkTreeViewColumn *column)
11218 {
11219   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11220   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11221   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11222
11223   if (tree_view->priv->focus_column == column)
11224     tree_view->priv->focus_column = NULL;
11225
11226   if (tree_view->priv->edited_column == column)
11227     {
11228       gtk_tree_view_stop_editing (tree_view, TRUE);
11229
11230       /* no need to, but just to be sure ... */
11231       tree_view->priv->edited_column = NULL;
11232     }
11233
11234   if (tree_view->priv->expander_column == column)
11235     tree_view->priv->expander_column = NULL;
11236
11237   g_signal_handlers_disconnect_by_func (column,
11238                                         G_CALLBACK (column_sizing_notify),
11239                                         tree_view);
11240
11241   _gtk_tree_view_column_unset_tree_view (column);
11242
11243   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11244   tree_view->priv->n_columns--;
11245
11246   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11247     {
11248       GList *list;
11249
11250       _gtk_tree_view_column_unrealize_button (column);
11251       for (list = tree_view->priv->columns; list; list = list->next)
11252         {
11253           GtkTreeViewColumn *tmp_column;
11254
11255           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11256           if (tmp_column->visible)
11257             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11258         }
11259
11260       if (tree_view->priv->n_columns == 0 &&
11261           gtk_tree_view_get_headers_visible (tree_view))
11262         gdk_window_hide (tree_view->priv->header_window);
11263
11264       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11265     }
11266
11267   g_object_unref (column);
11268   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11269
11270   return tree_view->priv->n_columns;
11271 }
11272
11273 /**
11274  * gtk_tree_view_insert_column:
11275  * @tree_view: A #GtkTreeView.
11276  * @column: The #GtkTreeViewColumn to be inserted.
11277  * @position: The position to insert @column in.
11278  *
11279  * This inserts the @column into the @tree_view at @position.  If @position is
11280  * -1, then the column is inserted at the end. If @tree_view has
11281  * "fixed_height" mode enabled, then @column must have its "sizing" property
11282  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11283  *
11284  * Return value: The number of columns in @tree_view after insertion.
11285  **/
11286 gint
11287 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11288                              GtkTreeViewColumn *column,
11289                              gint               position)
11290 {
11291   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11292   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11293   g_return_val_if_fail (column->tree_view == NULL, -1);
11294
11295   if (tree_view->priv->fixed_height_mode)
11296     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11297                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11298
11299   g_object_ref_sink (column);
11300
11301   if (tree_view->priv->n_columns == 0 &&
11302       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11303       gtk_tree_view_get_headers_visible (tree_view))
11304     {
11305       gdk_window_show (tree_view->priv->header_window);
11306     }
11307
11308   g_signal_connect (column, "notify::sizing",
11309                     G_CALLBACK (column_sizing_notify), tree_view);
11310
11311   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11312                                             column, position);
11313   tree_view->priv->n_columns++;
11314
11315   _gtk_tree_view_column_set_tree_view (column, tree_view);
11316
11317   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11318     {
11319       GList *list;
11320
11321       _gtk_tree_view_column_realize_button (column);
11322
11323       for (list = tree_view->priv->columns; list; list = list->next)
11324         {
11325           column = GTK_TREE_VIEW_COLUMN (list->data);
11326           if (column->visible)
11327             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11328         }
11329       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11330     }
11331
11332   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11333
11334   return tree_view->priv->n_columns;
11335 }
11336
11337 /**
11338  * gtk_tree_view_insert_column_with_attributes:
11339  * @tree_view: A #GtkTreeView
11340  * @position: The position to insert the new column in.
11341  * @title: The title to set the header to.
11342  * @cell: The #GtkCellRenderer.
11343  * @Varargs: A %NULL-terminated list of attributes.
11344  *
11345  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11346  * @position.  If @position is -1, then the newly created column is inserted at
11347  * the end.  The column is initialized with the attributes given. If @tree_view
11348  * has "fixed_height" mode enabled, then the new column will have its sizing
11349  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11350  *
11351  * Return value: The number of columns in @tree_view after insertion.
11352  **/
11353 gint
11354 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11355                                              gint             position,
11356                                              const gchar     *title,
11357                                              GtkCellRenderer *cell,
11358                                              ...)
11359 {
11360   GtkTreeViewColumn *column;
11361   gchar *attribute;
11362   va_list args;
11363   gint column_id;
11364
11365   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11366
11367   column = gtk_tree_view_column_new ();
11368   if (tree_view->priv->fixed_height_mode)
11369     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11370
11371   gtk_tree_view_column_set_title (column, title);
11372   gtk_tree_view_column_pack_start (column, cell, TRUE);
11373
11374   va_start (args, cell);
11375
11376   attribute = va_arg (args, gchar *);
11377
11378   while (attribute != NULL)
11379     {
11380       column_id = va_arg (args, gint);
11381       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11382       attribute = va_arg (args, gchar *);
11383     }
11384
11385   va_end (args);
11386
11387   gtk_tree_view_insert_column (tree_view, column, position);
11388
11389   return tree_view->priv->n_columns;
11390 }
11391
11392 /**
11393  * gtk_tree_view_insert_column_with_data_func:
11394  * @tree_view: a #GtkTreeView
11395  * @position: Position to insert, -1 for append
11396  * @title: column title
11397  * @cell: cell renderer for column
11398  * @func: function to set attributes of cell renderer
11399  * @data: data for @func
11400  * @dnotify: destroy notifier for @data
11401  *
11402  * Convenience function that inserts a new column into the #GtkTreeView
11403  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11404  * attributes (normally using data from the model). See also
11405  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11406  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11407  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11408  *
11409  * Return value: number of columns in the tree view post-insert
11410  **/
11411 gint
11412 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11413                                              gint                       position,
11414                                              const gchar               *title,
11415                                              GtkCellRenderer           *cell,
11416                                              GtkTreeCellDataFunc        func,
11417                                              gpointer                   data,
11418                                              GDestroyNotify             dnotify)
11419 {
11420   GtkTreeViewColumn *column;
11421
11422   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11423
11424   column = gtk_tree_view_column_new ();
11425   if (tree_view->priv->fixed_height_mode)
11426     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11427
11428   gtk_tree_view_column_set_title (column, title);
11429   gtk_tree_view_column_pack_start (column, cell, TRUE);
11430   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11431
11432   gtk_tree_view_insert_column (tree_view, column, position);
11433
11434   return tree_view->priv->n_columns;
11435 }
11436
11437 /**
11438  * gtk_tree_view_get_column:
11439  * @tree_view: A #GtkTreeView.
11440  * @n: The position of the column, counting from 0.
11441  *
11442  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11443  *
11444  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
11445  *     position is outside the range of columns.
11446  **/
11447 GtkTreeViewColumn *
11448 gtk_tree_view_get_column (GtkTreeView *tree_view,
11449                           gint         n)
11450 {
11451   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11452
11453   if (n < 0 || n >= tree_view->priv->n_columns)
11454     return NULL;
11455
11456   if (tree_view->priv->columns == NULL)
11457     return NULL;
11458
11459   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11460 }
11461
11462 /**
11463  * gtk_tree_view_get_columns:
11464  * @tree_view: A #GtkTreeView
11465  *
11466  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11467  * The returned list must be freed with g_list_free ().
11468  *
11469  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11470  **/
11471 GList *
11472 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11473 {
11474   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11475
11476   return g_list_copy (tree_view->priv->columns);
11477 }
11478
11479 /**
11480  * gtk_tree_view_move_column_after:
11481  * @tree_view: A #GtkTreeView
11482  * @column: The #GtkTreeViewColumn to be moved.
11483  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11484  *
11485  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11486  * @column is placed in the first position.
11487  **/
11488 void
11489 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11490                                  GtkTreeViewColumn *column,
11491                                  GtkTreeViewColumn *base_column)
11492 {
11493   GList *column_list_el, *base_el = NULL;
11494
11495   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11496
11497   column_list_el = g_list_find (tree_view->priv->columns, column);
11498   g_return_if_fail (column_list_el != NULL);
11499
11500   if (base_column)
11501     {
11502       base_el = g_list_find (tree_view->priv->columns, base_column);
11503       g_return_if_fail (base_el != NULL);
11504     }
11505
11506   if (column_list_el->prev == base_el)
11507     return;
11508
11509   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11510   if (base_el == NULL)
11511     {
11512       column_list_el->prev = NULL;
11513       column_list_el->next = tree_view->priv->columns;
11514       if (column_list_el->next)
11515         column_list_el->next->prev = column_list_el;
11516       tree_view->priv->columns = column_list_el;
11517     }
11518   else
11519     {
11520       column_list_el->prev = base_el;
11521       column_list_el->next = base_el->next;
11522       if (column_list_el->next)
11523         column_list_el->next->prev = column_list_el;
11524       base_el->next = column_list_el;
11525     }
11526
11527   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11528     {
11529       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11530       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11531     }
11532
11533   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11534 }
11535
11536 /**
11537  * gtk_tree_view_set_expander_column:
11538  * @tree_view: A #GtkTreeView
11539  * @column: %NULL, or the column to draw the expander arrow at.
11540  *
11541  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11542  * If @column is %NULL, then the expander arrow is always at the first 
11543  * visible column.
11544  *
11545  * If you do not want expander arrow to appear in your tree, set the 
11546  * expander column to a hidden column.
11547  **/
11548 void
11549 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11550                                    GtkTreeViewColumn *column)
11551 {
11552   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11553   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11554
11555   if (tree_view->priv->expander_column != column)
11556     {
11557       GList *list;
11558
11559       if (column)
11560         {
11561           /* Confirm that column is in tree_view */
11562           for (list = tree_view->priv->columns; list; list = list->next)
11563             if (list->data == column)
11564               break;
11565           g_return_if_fail (list != NULL);
11566         }
11567
11568       tree_view->priv->expander_column = column;
11569       g_object_notify (G_OBJECT (tree_view), "expander-column");
11570     }
11571 }
11572
11573 /**
11574  * gtk_tree_view_get_expander_column:
11575  * @tree_view: A #GtkTreeView
11576  *
11577  * Returns the column that is the current expander column.
11578  * This column has the expander arrow drawn next to it.
11579  *
11580  * Return value: (transfer none): The expander column.
11581  **/
11582 GtkTreeViewColumn *
11583 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11584 {
11585   GList *list;
11586
11587   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11588
11589   for (list = tree_view->priv->columns; list; list = list->next)
11590     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11591       return (GtkTreeViewColumn *) list->data;
11592   return NULL;
11593 }
11594
11595
11596 /**
11597  * gtk_tree_view_set_column_drag_function:
11598  * @tree_view: A #GtkTreeView.
11599  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11600  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11601  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11602  *
11603  * Sets a user function for determining where a column may be dropped when
11604  * dragged.  This function is called on every column pair in turn at the
11605  * beginning of a column drag to determine where a drop can take place.  The
11606  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11607  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11608  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11609  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11610  * @tree_view reverts to the default behavior of allowing all columns to be
11611  * dropped everywhere.
11612  **/
11613 void
11614 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11615                                         GtkTreeViewColumnDropFunc  func,
11616                                         gpointer                   user_data,
11617                                         GDestroyNotify             destroy)
11618 {
11619   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11620
11621   if (tree_view->priv->column_drop_func_data_destroy)
11622     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11623
11624   tree_view->priv->column_drop_func = func;
11625   tree_view->priv->column_drop_func_data = user_data;
11626   tree_view->priv->column_drop_func_data_destroy = destroy;
11627 }
11628
11629 /**
11630  * gtk_tree_view_scroll_to_point:
11631  * @tree_view: a #GtkTreeView
11632  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11633  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11634  *
11635  * Scrolls the tree view such that the top-left corner of the visible
11636  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11637  * in tree coordinates.  The @tree_view must be realized before
11638  * this function is called.  If it isn't, you probably want to be
11639  * using gtk_tree_view_scroll_to_cell().
11640  *
11641  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11642  **/
11643 void
11644 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11645                                gint         tree_x,
11646                                gint         tree_y)
11647 {
11648   GtkAdjustment *hadj;
11649   GtkAdjustment *vadj;
11650
11651   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11652   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11653
11654   hadj = tree_view->priv->hadjustment;
11655   vadj = tree_view->priv->vadjustment;
11656
11657   if (tree_x != -1)
11658     gtk_adjustment_set_value (hadj, tree_x);
11659   if (tree_y != -1)
11660     gtk_adjustment_set_value (vadj, tree_y);
11661 }
11662
11663 /**
11664  * gtk_tree_view_scroll_to_cell:
11665  * @tree_view: A #GtkTreeView.
11666  * @path: (allow-none): The path of the row to move to, or %NULL.
11667  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11668  * @use_align: whether to use alignment arguments, or %FALSE.
11669  * @row_align: The vertical alignment of the row specified by @path.
11670  * @col_align: The horizontal alignment of the column specified by @column.
11671  *
11672  * Moves the alignments of @tree_view to the position specified by @column and
11673  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11674  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11675  * or @path need to be non-%NULL.  @row_align determines where the row is
11676  * placed, and @col_align determines where @column is placed.  Both are expected
11677  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11678  * right/bottom alignment, 0.5 means center.
11679  *
11680  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11681  * tree does the minimum amount of work to scroll the cell onto the screen.
11682  * This means that the cell will be scrolled to the edge closest to its current
11683  * position.  If the cell is currently visible on the screen, nothing is done.
11684  *
11685  * This function only works if the model is set, and @path is a valid row on the
11686  * model.  If the model changes before the @tree_view is realized, the centered
11687  * path will be modified to reflect this change.
11688  **/
11689 void
11690 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11691                               GtkTreePath       *path,
11692                               GtkTreeViewColumn *column,
11693                               gboolean           use_align,
11694                               gfloat             row_align,
11695                               gfloat             col_align)
11696 {
11697   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11698   g_return_if_fail (tree_view->priv->model != NULL);
11699   g_return_if_fail (tree_view->priv->tree != NULL);
11700   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11701   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11702   g_return_if_fail (path != NULL || column != NULL);
11703
11704 #if 0
11705   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11706            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11707 #endif
11708   row_align = CLAMP (row_align, 0.0, 1.0);
11709   col_align = CLAMP (col_align, 0.0, 1.0);
11710
11711
11712   /* Note: Despite the benefits that come from having one code path for the
11713    * scrolling code, we short-circuit validate_visible_area's immplementation as
11714    * it is much slower than just going to the point.
11715    */
11716   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11717       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11718       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11719       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11720     {
11721       if (tree_view->priv->scroll_to_path)
11722         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11723
11724       tree_view->priv->scroll_to_path = NULL;
11725       tree_view->priv->scroll_to_column = NULL;
11726
11727       if (path)
11728         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11729       if (column)
11730         tree_view->priv->scroll_to_column = column;
11731       tree_view->priv->scroll_to_use_align = use_align;
11732       tree_view->priv->scroll_to_row_align = row_align;
11733       tree_view->priv->scroll_to_col_align = col_align;
11734
11735       install_presize_handler (tree_view);
11736     }
11737   else
11738     {
11739       GdkRectangle cell_rect;
11740       GdkRectangle vis_rect;
11741       gint dest_x, dest_y;
11742
11743       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11744       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11745
11746       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11747
11748       dest_x = vis_rect.x;
11749       dest_y = vis_rect.y;
11750
11751       if (column)
11752         {
11753           if (use_align)
11754             {
11755               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11756             }
11757           else
11758             {
11759               if (cell_rect.x < vis_rect.x)
11760                 dest_x = cell_rect.x;
11761               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11762                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11763             }
11764         }
11765
11766       if (path)
11767         {
11768           if (use_align)
11769             {
11770               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11771               dest_y = MAX (dest_y, 0);
11772             }
11773           else
11774             {
11775               if (cell_rect.y < vis_rect.y)
11776                 dest_y = cell_rect.y;
11777               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11778                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11779             }
11780         }
11781
11782       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11783     }
11784 }
11785
11786 /**
11787  * gtk_tree_view_row_activated:
11788  * @tree_view: A #GtkTreeView
11789  * @path: The #GtkTreePath to be activated.
11790  * @column: The #GtkTreeViewColumn to be activated.
11791  *
11792  * Activates the cell determined by @path and @column.
11793  **/
11794 void
11795 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11796                              GtkTreePath       *path,
11797                              GtkTreeViewColumn *column)
11798 {
11799   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11800
11801   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11802 }
11803
11804
11805 static void
11806 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11807                                           GtkRBNode *node,
11808                                           gpointer   data)
11809 {
11810   GtkTreeView *tree_view = data;
11811
11812   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11813       node->children)
11814     {
11815       GtkTreePath *path;
11816       GtkTreeIter iter;
11817
11818       path = _gtk_tree_view_find_path (tree_view, tree, node);
11819       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11820
11821       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11822
11823       gtk_tree_path_free (path);
11824     }
11825
11826   if (node->children)
11827     _gtk_rbtree_traverse (node->children,
11828                           node->children->root,
11829                           G_PRE_ORDER,
11830                           gtk_tree_view_expand_all_emission_helper,
11831                           tree_view);
11832 }
11833
11834 /**
11835  * gtk_tree_view_expand_all:
11836  * @tree_view: A #GtkTreeView.
11837  *
11838  * Recursively expands all nodes in the @tree_view.
11839  **/
11840 void
11841 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11842 {
11843   GtkTreePath *path;
11844   GtkRBTree *tree;
11845   GtkRBNode *node;
11846
11847   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11848
11849   if (tree_view->priv->tree == NULL)
11850     return;
11851
11852   path = gtk_tree_path_new_first ();
11853   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11854
11855   while (node)
11856     {
11857       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11858       node = _gtk_rbtree_next (tree, node);
11859       gtk_tree_path_next (path);
11860   }
11861
11862   gtk_tree_path_free (path);
11863 }
11864
11865 /* Timeout to animate the expander during expands and collapses */
11866 static gboolean
11867 expand_collapse_timeout (gpointer data)
11868 {
11869   return do_expand_collapse (data);
11870 }
11871
11872 static void
11873 add_expand_collapse_timeout (GtkTreeView *tree_view,
11874                              GtkRBTree   *tree,
11875                              GtkRBNode   *node,
11876                              gboolean     expand)
11877 {
11878   if (tree_view->priv->expand_collapse_timeout != 0)
11879     return;
11880
11881   tree_view->priv->expand_collapse_timeout =
11882       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11883   tree_view->priv->expanded_collapsed_tree = tree;
11884   tree_view->priv->expanded_collapsed_node = node;
11885
11886   if (expand)
11887     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11888   else
11889     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11890 }
11891
11892 static void
11893 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11894 {
11895   if (tree_view->priv->expand_collapse_timeout)
11896     {
11897       g_source_remove (tree_view->priv->expand_collapse_timeout);
11898       tree_view->priv->expand_collapse_timeout = 0;
11899     }
11900
11901   if (tree_view->priv->expanded_collapsed_node != NULL)
11902     {
11903       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11904       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11905
11906       tree_view->priv->expanded_collapsed_node = NULL;
11907     }
11908 }
11909
11910 static void
11911 cancel_arrow_animation (GtkTreeView *tree_view)
11912 {
11913   if (tree_view->priv->expand_collapse_timeout)
11914     {
11915       while (do_expand_collapse (tree_view));
11916
11917       remove_expand_collapse_timeout (tree_view);
11918     }
11919 }
11920
11921 static gboolean
11922 do_expand_collapse (GtkTreeView *tree_view)
11923 {
11924   GtkRBNode *node;
11925   GtkRBTree *tree;
11926   gboolean expanding;
11927   gboolean redraw;
11928
11929   redraw = FALSE;
11930   expanding = TRUE;
11931
11932   node = tree_view->priv->expanded_collapsed_node;
11933   tree = tree_view->priv->expanded_collapsed_tree;
11934
11935   if (node->children == NULL)
11936     expanding = FALSE;
11937
11938   if (expanding)
11939     {
11940       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11941         {
11942           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11943           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11944
11945           redraw = TRUE;
11946
11947         }
11948       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11949         {
11950           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11951
11952           redraw = TRUE;
11953         }
11954     }
11955   else
11956     {
11957       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11958         {
11959           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11960           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11961
11962           redraw = TRUE;
11963         }
11964       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11965         {
11966           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11967
11968           redraw = TRUE;
11969
11970         }
11971     }
11972
11973   if (redraw)
11974     {
11975       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
11976
11977       return TRUE;
11978     }
11979
11980   return FALSE;
11981 }
11982
11983 /**
11984  * gtk_tree_view_collapse_all:
11985  * @tree_view: A #GtkTreeView.
11986  *
11987  * Recursively collapses all visible, expanded nodes in @tree_view.
11988  **/
11989 void
11990 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11991 {
11992   GtkRBTree *tree;
11993   GtkRBNode *node;
11994   GtkTreePath *path;
11995   gint *indices;
11996
11997   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11998
11999   if (tree_view->priv->tree == NULL)
12000     return;
12001
12002   path = gtk_tree_path_new ();
12003   gtk_tree_path_down (path);
12004   indices = gtk_tree_path_get_indices (path);
12005
12006   tree = tree_view->priv->tree;
12007   node = tree->root;
12008   while (node && node->left != tree->nil)
12009     node = node->left;
12010
12011   while (node)
12012     {
12013       if (node->children)
12014         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12015       indices[0]++;
12016       node = _gtk_rbtree_next (tree, node);
12017     }
12018
12019   gtk_tree_path_free (path);
12020 }
12021
12022 /**
12023  * gtk_tree_view_expand_to_path:
12024  * @tree_view: A #GtkTreeView.
12025  * @path: path to a row.
12026  *
12027  * Expands the row at @path. This will also expand all parent rows of
12028  * @path as necessary.
12029  *
12030  * Since: 2.2
12031  **/
12032 void
12033 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12034                               GtkTreePath *path)
12035 {
12036   gint i, depth;
12037   gint *indices;
12038   GtkTreePath *tmp;
12039
12040   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12041   g_return_if_fail (path != NULL);
12042
12043   depth = gtk_tree_path_get_depth (path);
12044   indices = gtk_tree_path_get_indices (path);
12045
12046   tmp = gtk_tree_path_new ();
12047   g_return_if_fail (tmp != NULL);
12048
12049   for (i = 0; i < depth; i++)
12050     {
12051       gtk_tree_path_append_index (tmp, indices[i]);
12052       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12053     }
12054
12055   gtk_tree_path_free (tmp);
12056 }
12057
12058 /* FIXME the bool return values for expand_row and collapse_row are
12059  * not analagous; they should be TRUE if the row had children and
12060  * was not already in the requested state.
12061  */
12062
12063
12064 static gboolean
12065 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12066                                GtkTreePath *path,
12067                                GtkRBTree   *tree,
12068                                GtkRBNode   *node,
12069                                gboolean     open_all,
12070                                gboolean     animate)
12071 {
12072   GtkTreeIter iter;
12073   GtkTreeIter temp;
12074   gboolean expand;
12075
12076   if (animate)
12077     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12078                   "gtk-enable-animations", &animate,
12079                   NULL);
12080
12081   remove_auto_expand_timeout (tree_view);
12082
12083   if (node->children && !open_all)
12084     return FALSE;
12085
12086   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12087     return FALSE;
12088
12089   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12090   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12091     return FALSE;
12092
12093
12094    if (node->children && open_all)
12095     {
12096       gboolean retval = FALSE;
12097       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12098
12099       gtk_tree_path_append_index (tmp_path, 0);
12100       tree = node->children;
12101       node = tree->root;
12102       while (node->left != tree->nil)
12103         node = node->left;
12104       /* try to expand the children */
12105       do
12106         {
12107          gboolean t;
12108          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12109                                             TRUE, animate);
12110          if (t)
12111            retval = TRUE;
12112
12113          gtk_tree_path_next (tmp_path);
12114          node = _gtk_rbtree_next (tree, node);
12115        }
12116       while (node != NULL);
12117
12118       gtk_tree_path_free (tmp_path);
12119
12120       return retval;
12121     }
12122
12123   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12124
12125   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12126     return FALSE;
12127
12128   if (expand)
12129     return FALSE;
12130
12131   node->children = _gtk_rbtree_new ();
12132   node->children->parent_tree = tree;
12133   node->children->parent_node = node;
12134
12135   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12136
12137   gtk_tree_view_build_tree (tree_view,
12138                             node->children,
12139                             &temp,
12140                             gtk_tree_path_get_depth (path) + 1,
12141                             open_all);
12142
12143   remove_expand_collapse_timeout (tree_view);
12144
12145   if (animate)
12146     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12147
12148   install_presize_handler (tree_view);
12149
12150   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12151   if (open_all && node->children)
12152     {
12153       _gtk_rbtree_traverse (node->children,
12154                             node->children->root,
12155                             G_PRE_ORDER,
12156                             gtk_tree_view_expand_all_emission_helper,
12157                             tree_view);
12158     }
12159   return TRUE;
12160 }
12161
12162
12163 /**
12164  * gtk_tree_view_expand_row:
12165  * @tree_view: a #GtkTreeView
12166  * @path: path to a row
12167  * @open_all: whether to recursively expand, or just expand immediate children
12168  *
12169  * Opens the row so its children are visible.
12170  *
12171  * Return value: %TRUE if the row existed and had children
12172  **/
12173 gboolean
12174 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12175                           GtkTreePath *path,
12176                           gboolean     open_all)
12177 {
12178   GtkRBTree *tree;
12179   GtkRBNode *node;
12180
12181   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12182   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12183   g_return_val_if_fail (path != NULL, FALSE);
12184
12185   if (_gtk_tree_view_find_node (tree_view,
12186                                 path,
12187                                 &tree,
12188                                 &node))
12189     return FALSE;
12190
12191   if (tree != NULL)
12192     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12193   else
12194     return FALSE;
12195 }
12196
12197 static gboolean
12198 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12199                                  GtkTreePath *path,
12200                                  GtkRBTree   *tree,
12201                                  GtkRBNode   *node,
12202                                  gboolean     animate)
12203 {
12204   GtkTreeIter iter;
12205   GtkTreeIter children;
12206   gboolean collapse;
12207   gint x, y;
12208   GList *list;
12209   GdkWindow *child, *parent;
12210
12211   if (animate)
12212     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12213                   "gtk-enable-animations", &animate,
12214                   NULL);
12215
12216   remove_auto_expand_timeout (tree_view);
12217
12218   if (node->children == NULL)
12219     return FALSE;
12220
12221   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12222
12223   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12224
12225   if (collapse)
12226     return FALSE;
12227
12228   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12229    * a chance to prelight the correct node below */
12230
12231   if (tree_view->priv->prelight_tree)
12232     {
12233       GtkRBTree *parent_tree;
12234       GtkRBNode *parent_node;
12235
12236       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12237       parent_node = tree_view->priv->prelight_tree->parent_node;
12238       while (parent_tree)
12239         {
12240           if (parent_tree == tree && parent_node == node)
12241             {
12242               ensure_unprelighted (tree_view);
12243               break;
12244             }
12245           parent_node = parent_tree->parent_node;
12246           parent_tree = parent_tree->parent_tree;
12247         }
12248     }
12249
12250   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12251
12252   for (list = tree_view->priv->columns; list; list = list->next)
12253     {
12254       GtkTreeViewColumn *column = list->data;
12255
12256       if (column->visible == FALSE)
12257         continue;
12258       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12259         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12260     }
12261
12262   if (tree_view->priv->destroy_count_func)
12263     {
12264       GtkTreePath *child_path;
12265       gint child_count = 0;
12266       child_path = gtk_tree_path_copy (path);
12267       gtk_tree_path_down (child_path);
12268       if (node->children)
12269         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12270       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12271       gtk_tree_path_free (child_path);
12272     }
12273
12274   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12275     {
12276       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12277
12278       if (gtk_tree_path_is_ancestor (path, cursor_path))
12279         {
12280           gtk_tree_row_reference_free (tree_view->priv->cursor);
12281           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12282                                                                       tree_view->priv->model,
12283                                                                       path);
12284         }
12285       gtk_tree_path_free (cursor_path);
12286     }
12287
12288   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12289     {
12290       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12291       if (gtk_tree_path_is_ancestor (path, anchor_path))
12292         {
12293           gtk_tree_row_reference_free (tree_view->priv->anchor);
12294           tree_view->priv->anchor = NULL;
12295         }
12296       gtk_tree_path_free (anchor_path);
12297     }
12298
12299   /* Stop a pending double click */
12300   tree_view->priv->last_button_x = -1;
12301   tree_view->priv->last_button_y = -1;
12302
12303   remove_expand_collapse_timeout (tree_view);
12304
12305   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12306     {
12307       _gtk_rbtree_remove (node->children);
12308       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12309     }
12310   else
12311     _gtk_rbtree_remove (node->children);
12312   
12313   if (animate)
12314     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12315   
12316   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12317     {
12318       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12319     }
12320
12321   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12322
12323   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12324     {
12325       /* now that we've collapsed all rows, we want to try to set the prelight
12326        * again. To do this, we fake a motion event and send it to ourselves. */
12327
12328       child = tree_view->priv->bin_window;
12329       parent = gdk_window_get_parent (child);
12330
12331       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12332         {
12333           GdkEventMotion event;
12334           gint child_x, child_y;
12335
12336           gdk_window_get_position (child, &child_x, &child_y);
12337
12338           event.window = tree_view->priv->bin_window;
12339           event.x = x - child_x;
12340           event.y = y - child_y;
12341
12342           /* despite the fact this isn't a real event, I'm almost positive it will
12343            * never trigger a drag event.  maybe_drag is the only function that uses
12344            * more than just event.x and event.y. */
12345           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12346         }
12347     }
12348
12349   return TRUE;
12350 }
12351
12352 /**
12353  * gtk_tree_view_collapse_row:
12354  * @tree_view: a #GtkTreeView
12355  * @path: path to a row in the @tree_view
12356  *
12357  * Collapses a row (hides its child rows, if they exist).
12358  *
12359  * Return value: %TRUE if the row was collapsed.
12360  **/
12361 gboolean
12362 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12363                             GtkTreePath *path)
12364 {
12365   GtkRBTree *tree;
12366   GtkRBNode *node;
12367
12368   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12369   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12370   g_return_val_if_fail (path != NULL, FALSE);
12371
12372   if (_gtk_tree_view_find_node (tree_view,
12373                                 path,
12374                                 &tree,
12375                                 &node))
12376     return FALSE;
12377
12378   if (tree == NULL || node->children == NULL)
12379     return FALSE;
12380
12381   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12382 }
12383
12384 static void
12385 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12386                                         GtkRBTree              *tree,
12387                                         GtkTreePath            *path,
12388                                         GtkTreeViewMappingFunc  func,
12389                                         gpointer                user_data)
12390 {
12391   GtkRBNode *node;
12392
12393   if (tree == NULL || tree->root == NULL)
12394     return;
12395
12396   node = tree->root;
12397
12398   while (node && node->left != tree->nil)
12399     node = node->left;
12400
12401   while (node)
12402     {
12403       if (node->children)
12404         {
12405           (* func) (tree_view, path, user_data);
12406           gtk_tree_path_down (path);
12407           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12408           gtk_tree_path_up (path);
12409         }
12410       gtk_tree_path_next (path);
12411       node = _gtk_rbtree_next (tree, node);
12412     }
12413 }
12414
12415 /**
12416  * gtk_tree_view_map_expanded_rows:
12417  * @tree_view: A #GtkTreeView
12418  * @func: (scope call): A function to be called
12419  * @data: User data to be passed to the function.
12420  *
12421  * Calls @func on all expanded rows.
12422  **/
12423 void
12424 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12425                                  GtkTreeViewMappingFunc  func,
12426                                  gpointer                user_data)
12427 {
12428   GtkTreePath *path;
12429
12430   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12431   g_return_if_fail (func != NULL);
12432
12433   path = gtk_tree_path_new_first ();
12434
12435   gtk_tree_view_map_expanded_rows_helper (tree_view,
12436                                           tree_view->priv->tree,
12437                                           path, func, user_data);
12438
12439   gtk_tree_path_free (path);
12440 }
12441
12442 /**
12443  * gtk_tree_view_row_expanded:
12444  * @tree_view: A #GtkTreeView.
12445  * @path: A #GtkTreePath to test expansion state.
12446  *
12447  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12448  *
12449  * Return value: %TRUE if #path is expanded.
12450  **/
12451 gboolean
12452 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12453                             GtkTreePath *path)
12454 {
12455   GtkRBTree *tree;
12456   GtkRBNode *node;
12457
12458   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12459   g_return_val_if_fail (path != NULL, FALSE);
12460
12461   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12462
12463   if (node == NULL)
12464     return FALSE;
12465
12466   return (node->children != NULL);
12467 }
12468
12469 /**
12470  * gtk_tree_view_get_reorderable:
12471  * @tree_view: a #GtkTreeView
12472  *
12473  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12474  * gtk_tree_view_set_reorderable().
12475  *
12476  * Return value: %TRUE if the tree can be reordered.
12477  **/
12478 gboolean
12479 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12480 {
12481   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12482
12483   return tree_view->priv->reorderable;
12484 }
12485
12486 /**
12487  * gtk_tree_view_set_reorderable:
12488  * @tree_view: A #GtkTreeView.
12489  * @reorderable: %TRUE, if the tree can be reordered.
12490  *
12491  * This function is a convenience function to allow you to reorder
12492  * models that support the #GtkDragSourceIface and the
12493  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12494  * these.  If @reorderable is %TRUE, then the user can reorder the
12495  * model by dragging and dropping rows. The developer can listen to
12496  * these changes by connecting to the model's row_inserted and
12497  * row_deleted signals. The reordering is implemented by setting up
12498  * the tree view as a drag source and destination. Therefore, drag and
12499  * drop can not be used in a reorderable view for any other purpose.
12500  *
12501  * This function does not give you any degree of control over the order -- any
12502  * reordering is allowed.  If more control is needed, you should probably
12503  * handle drag and drop manually.
12504  **/
12505 void
12506 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12507                                gboolean     reorderable)
12508 {
12509   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12510
12511   reorderable = reorderable != FALSE;
12512
12513   if (tree_view->priv->reorderable == reorderable)
12514     return;
12515
12516   if (reorderable)
12517     {
12518       const GtkTargetEntry row_targets[] = {
12519         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12520       };
12521
12522       gtk_tree_view_enable_model_drag_source (tree_view,
12523                                               GDK_BUTTON1_MASK,
12524                                               row_targets,
12525                                               G_N_ELEMENTS (row_targets),
12526                                               GDK_ACTION_MOVE);
12527       gtk_tree_view_enable_model_drag_dest (tree_view,
12528                                             row_targets,
12529                                             G_N_ELEMENTS (row_targets),
12530                                             GDK_ACTION_MOVE);
12531     }
12532   else
12533     {
12534       gtk_tree_view_unset_rows_drag_source (tree_view);
12535       gtk_tree_view_unset_rows_drag_dest (tree_view);
12536     }
12537
12538   tree_view->priv->reorderable = reorderable;
12539
12540   g_object_notify (G_OBJECT (tree_view), "reorderable");
12541 }
12542
12543 static void
12544 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12545                                GtkTreePath     *path,
12546                                gboolean         clear_and_select,
12547                                gboolean         clamp_node)
12548 {
12549   GtkRBTree *tree = NULL;
12550   GtkRBNode *node = NULL;
12551
12552   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12553     {
12554       GtkTreePath *cursor_path;
12555       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12556       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12557       gtk_tree_path_free (cursor_path);
12558     }
12559
12560   gtk_tree_row_reference_free (tree_view->priv->cursor);
12561   tree_view->priv->cursor = NULL;
12562
12563   /* One cannot set the cursor on a separator.   Also, if
12564    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12565    * before finding the tree and node belonging to path.  The
12566    * path maps to a non-existing path and we will silently bail out.
12567    * We unset tree and node to avoid further processing.
12568    */
12569   if (!row_is_separator (tree_view, NULL, path)
12570       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12571     {
12572       tree_view->priv->cursor =
12573           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12574                                             tree_view->priv->model,
12575                                             path);
12576     }
12577   else
12578     {
12579       tree = NULL;
12580       node = NULL;
12581     }
12582
12583   if (tree != NULL)
12584     {
12585       GtkRBTree *new_tree = NULL;
12586       GtkRBNode *new_node = NULL;
12587
12588       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12589         {
12590           GtkTreeSelectMode mode = 0;
12591
12592           if (tree_view->priv->ctrl_pressed)
12593             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12594           if (tree_view->priv->shift_pressed)
12595             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12596
12597           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12598                                                     node, tree, path, mode,
12599                                                     FALSE);
12600         }
12601
12602       /* We have to re-find tree and node here again, somebody might have
12603        * cleared the node or the whole tree in the GtkTreeSelection::changed
12604        * callback. If the nodes differ we bail out here.
12605        */
12606       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12607
12608       if (tree != new_tree || node != new_node)
12609         return;
12610
12611       if (clamp_node)
12612         {
12613           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12614           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12615         }
12616     }
12617
12618   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12619 }
12620
12621 /**
12622  * gtk_tree_view_get_cursor:
12623  * @tree_view: A #GtkTreeView
12624  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12625  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12626  *
12627  * Fills in @path and @focus_column with the current path and focus column.  If
12628  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12629  * currently has focus, then *@focus_column will be %NULL.
12630  *
12631  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12632  * you are done with it.
12633  **/
12634 void
12635 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12636                           GtkTreePath       **path,
12637                           GtkTreeViewColumn **focus_column)
12638 {
12639   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12640
12641   if (path)
12642     {
12643       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12644         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12645       else
12646         *path = NULL;
12647     }
12648
12649   if (focus_column)
12650     {
12651       *focus_column = tree_view->priv->focus_column;
12652     }
12653 }
12654
12655 /**
12656  * gtk_tree_view_set_cursor:
12657  * @tree_view: A #GtkTreeView
12658  * @path: A #GtkTreePath
12659  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12660  * @start_editing: %TRUE if the specified cell should start being edited.
12661  *
12662  * Sets the current keyboard focus to be at @path, and selects it.  This is
12663  * useful when you want to focus the user's attention on a particular row.  If
12664  * @focus_column is not %NULL, then focus is given to the column specified by 
12665  * it. Additionally, if @focus_column is specified, and @start_editing is 
12666  * %TRUE, then editing should be started in the specified cell.  
12667  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12668  * in order to give keyboard focus to the widget.  Please note that editing 
12669  * can only happen when the widget is realized.
12670  *
12671  * If @path is invalid for @model, the current cursor (if any) will be unset
12672  * and the function will return without failing.
12673  **/
12674 void
12675 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12676                           GtkTreePath       *path,
12677                           GtkTreeViewColumn *focus_column,
12678                           gboolean           start_editing)
12679 {
12680   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12681                                     NULL, start_editing);
12682 }
12683
12684 /**
12685  * gtk_tree_view_set_cursor_on_cell:
12686  * @tree_view: A #GtkTreeView
12687  * @path: A #GtkTreePath
12688  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12689  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12690  * @start_editing: %TRUE if the specified cell should start being edited.
12691  *
12692  * Sets the current keyboard focus to be at @path, and selects it.  This is
12693  * useful when you want to focus the user's attention on a particular row.  If
12694  * @focus_column is not %NULL, then focus is given to the column specified by
12695  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12696  * contains 2 or more editable or activatable cells, then focus is given to
12697  * the cell specified by @focus_cell. Additionally, if @focus_column is
12698  * specified, and @start_editing is %TRUE, then editing should be started in
12699  * the specified cell.  This function is often followed by
12700  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12701  * widget.  Please note that editing can only happen when the widget is
12702  * realized.
12703  *
12704  * If @path is invalid for @model, the current cursor (if any) will be unset
12705  * and the function will return without failing.
12706  *
12707  * Since: 2.2
12708  **/
12709 void
12710 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12711                                   GtkTreePath       *path,
12712                                   GtkTreeViewColumn *focus_column,
12713                                   GtkCellRenderer   *focus_cell,
12714                                   gboolean           start_editing)
12715 {
12716   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12717   g_return_if_fail (path != NULL);
12718   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12719
12720   if (!tree_view->priv->model)
12721     return;
12722
12723   if (focus_cell)
12724     {
12725       g_return_if_fail (focus_column);
12726       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12727     }
12728
12729   /* cancel the current editing, if it exists */
12730   if (tree_view->priv->edited_column &&
12731       tree_view->priv->edited_column->editable_widget)
12732     gtk_tree_view_stop_editing (tree_view, TRUE);
12733
12734   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12735
12736   if (focus_column && focus_column->visible)
12737     {
12738       GList *list;
12739       gboolean column_in_tree = FALSE;
12740
12741       for (list = tree_view->priv->columns; list; list = list->next)
12742         if (list->data == focus_column)
12743           {
12744             column_in_tree = TRUE;
12745             break;
12746           }
12747       g_return_if_fail (column_in_tree);
12748       tree_view->priv->focus_column = focus_column;
12749       if (focus_cell)
12750         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12751       if (start_editing)
12752         gtk_tree_view_start_editing (tree_view, path);
12753     }
12754 }
12755
12756 /**
12757  * gtk_tree_view_get_bin_window:
12758  * @tree_view: A #GtkTreeView
12759  *
12760  * Returns the window that @tree_view renders to.
12761  * This is used primarily to compare to <literal>event->window</literal>
12762  * to confirm that the event on @tree_view is on the right window.
12763  *
12764  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
12765  *     hasn't been realized yet
12766  **/
12767 GdkWindow *
12768 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12769 {
12770   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12771
12772   return tree_view->priv->bin_window;
12773 }
12774
12775 /**
12776  * gtk_tree_view_get_path_at_pos:
12777  * @tree_view: A #GtkTreeView.
12778  * @x: The x position to be identified (relative to bin_window).
12779  * @y: The y position to be identified (relative to bin_window).
12780  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12781  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12782  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12783  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12784  *
12785  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12786  * (please see gtk_tree_view_get_bin_window()).
12787  * That is, @x and @y are relative to an events coordinates. @x and @y must
12788  * come from an event on the @tree_view only where <literal>event->window ==
12789  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12790  * things like popup menus. If @path is non-%NULL, then it will be filled
12791  * with the #GtkTreePath at that point.  This path should be freed with
12792  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12793  * with the column at that point.  @cell_x and @cell_y return the coordinates
12794  * relative to the cell background (i.e. the @background_area passed to
12795  * gtk_cell_renderer_render()).  This function is only meaningful if
12796  * @tree_view is realized.  Therefore this function will always return %FALSE
12797  * if @tree_view is not realized or does not have a model.
12798  *
12799  * For converting widget coordinates (eg. the ones you get from
12800  * GtkWidget::query-tooltip), please see
12801  * gtk_tree_view_convert_widget_to_bin_window_coords().
12802  *
12803  * Return value: %TRUE if a row exists at that coordinate.
12804  **/
12805 gboolean
12806 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12807                                gint                x,
12808                                gint                y,
12809                                GtkTreePath       **path,
12810                                GtkTreeViewColumn **column,
12811                                gint               *cell_x,
12812                                gint               *cell_y)
12813 {
12814   GtkRBTree *tree;
12815   GtkRBNode *node;
12816   gint y_offset;
12817
12818   g_return_val_if_fail (tree_view != NULL, FALSE);
12819
12820   if (path)
12821     *path = NULL;
12822   if (column)
12823     *column = NULL;
12824
12825   if (tree_view->priv->bin_window == NULL)
12826     return FALSE;
12827
12828   if (tree_view->priv->tree == NULL)
12829     return FALSE;
12830
12831   if (x > tree_view->priv->hadjustment->upper)
12832     return FALSE;
12833
12834   if (x < 0 || y < 0)
12835     return FALSE;
12836
12837   if (column || cell_x)
12838     {
12839       GtkTreeViewColumn *tmp_column;
12840       GtkTreeViewColumn *last_column = NULL;
12841       GList *list;
12842       gint remaining_x = x;
12843       gboolean found = FALSE;
12844       gboolean rtl;
12845
12846       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12847       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12848            list;
12849            list = (rtl ? list->prev : list->next))
12850         {
12851           tmp_column = list->data;
12852
12853           if (tmp_column->visible == FALSE)
12854             continue;
12855
12856           last_column = tmp_column;
12857           if (remaining_x <= tmp_column->width)
12858             {
12859               found = TRUE;
12860
12861               if (column)
12862                 *column = tmp_column;
12863
12864               if (cell_x)
12865                 *cell_x = remaining_x;
12866
12867               break;
12868             }
12869           remaining_x -= tmp_column->width;
12870         }
12871
12872       /* If found is FALSE and there is a last_column, then it the remainder
12873        * space is in that area
12874        */
12875       if (!found)
12876         {
12877           if (last_column)
12878             {
12879               if (column)
12880                 *column = last_column;
12881               
12882               if (cell_x)
12883                 *cell_x = last_column->width + remaining_x;
12884             }
12885           else
12886             {
12887               return FALSE;
12888             }
12889         }
12890     }
12891
12892   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12893                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12894                                       &tree, &node);
12895
12896   if (tree == NULL)
12897     return FALSE;
12898
12899   if (cell_y)
12900     *cell_y = y_offset;
12901
12902   if (path)
12903     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12904
12905   return TRUE;
12906 }
12907
12908
12909 /**
12910  * gtk_tree_view_get_cell_area:
12911  * @tree_view: a #GtkTreeView
12912  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12913  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12914  * @rect: rectangle to fill with cell rect
12915  *
12916  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12917  * row specified by @path and the column specified by @column.  If @path is
12918  * %NULL, or points to a path not currently displayed, the @y and @height fields
12919  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12920  * fields will be filled with 0.  The sum of all cell rects does not cover the
12921  * entire tree; there are extra pixels in between rows, for example. The
12922  * returned rectangle is equivalent to the @cell_area passed to
12923  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12924  * realized.
12925  **/
12926 void
12927 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12928                              GtkTreePath        *path,
12929                              GtkTreeViewColumn  *column,
12930                              GdkRectangle       *rect)
12931 {
12932   GtkAllocation allocation;
12933   GtkRBTree *tree = NULL;
12934   GtkRBNode *node = NULL;
12935   gint vertical_separator;
12936   gint horizontal_separator;
12937
12938   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12939   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12940   g_return_if_fail (rect != NULL);
12941   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12942   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12943
12944   gtk_widget_style_get (GTK_WIDGET (tree_view),
12945                         "vertical-separator", &vertical_separator,
12946                         "horizontal-separator", &horizontal_separator,
12947                         NULL);
12948
12949   rect->x = 0;
12950   rect->y = 0;
12951   rect->width = 0;
12952   rect->height = 0;
12953
12954   if (column)
12955     {
12956       gtk_widget_get_allocation (column->button, &allocation);
12957       rect->x = allocation.x + horizontal_separator/2;
12958       rect->width = allocation.width - horizontal_separator;
12959     }
12960
12961   if (path)
12962     {
12963       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12964
12965       /* Get vertical coords */
12966       if ((!ret && tree == NULL) || ret)
12967         return;
12968
12969       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12970       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12971
12972       if (column &&
12973           gtk_tree_view_is_expander_column (tree_view, column))
12974         {
12975           gint depth = gtk_tree_path_get_depth (path);
12976           gboolean rtl;
12977
12978           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12979
12980           if (!rtl)
12981             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12982           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12983
12984           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12985             {
12986               if (!rtl)
12987                 rect->x += depth * tree_view->priv->expander_size;
12988               rect->width -= depth * tree_view->priv->expander_size;
12989             }
12990
12991           rect->width = MAX (rect->width, 0);
12992         }
12993     }
12994 }
12995
12996 /**
12997  * gtk_tree_view_get_background_area:
12998  * @tree_view: a #GtkTreeView
12999  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13000  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13001  * @rect: rectangle to fill with cell background rect
13002  *
13003  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13004  * row specified by @path and the column specified by @column.  If @path is
13005  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13006  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13007  * fields will be filled with 0.  The returned rectangle is equivalent to the
13008  * @background_area passed to gtk_cell_renderer_render().  These background
13009  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13010  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13011  * itself, excluding surrounding borders and the tree expander area.
13012  *
13013  **/
13014 void
13015 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13016                                    GtkTreePath        *path,
13017                                    GtkTreeViewColumn  *column,
13018                                    GdkRectangle       *rect)
13019 {
13020   GtkRBTree *tree = NULL;
13021   GtkRBNode *node = NULL;
13022
13023   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13024   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13025   g_return_if_fail (rect != NULL);
13026
13027   rect->x = 0;
13028   rect->y = 0;
13029   rect->width = 0;
13030   rect->height = 0;
13031
13032   if (path)
13033     {
13034       /* Get vertical coords */
13035
13036       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13037           tree == NULL)
13038         return;
13039
13040       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13041
13042       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13043     }
13044
13045   if (column)
13046     {
13047       gint x2 = 0;
13048
13049       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13050       rect->width = x2 - rect->x;
13051     }
13052 }
13053
13054 /**
13055  * gtk_tree_view_get_visible_rect:
13056  * @tree_view: a #GtkTreeView
13057  * @visible_rect: rectangle to fill
13058  *
13059  * Fills @visible_rect with the currently-visible region of the
13060  * buffer, in tree coordinates. Convert to bin_window coordinates with
13061  * gtk_tree_view_convert_tree_to_bin_window_coords().
13062  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13063  * scrollable area of the tree.
13064  **/
13065 void
13066 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13067                                 GdkRectangle *visible_rect)
13068 {
13069   GtkAllocation allocation;
13070   GtkWidget *widget;
13071
13072   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13073
13074   widget = GTK_WIDGET (tree_view);
13075
13076   if (visible_rect)
13077     {
13078       gtk_widget_get_allocation (widget, &allocation);
13079       visible_rect->x = tree_view->priv->hadjustment->value;
13080       visible_rect->y = tree_view->priv->vadjustment->value;
13081       visible_rect->width = allocation.width;
13082       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13083     }
13084 }
13085
13086 /**
13087  * gtk_tree_view_convert_widget_to_tree_coords:
13088  * @tree_view: a #GtkTreeView
13089  * @wx: X coordinate relative to the widget
13090  * @wy: Y coordinate relative to the widget
13091  * @tx: return location for tree X coordinate
13092  * @ty: return location for tree Y coordinate
13093  *
13094  * Converts widget coordinates to coordinates for the
13095  * tree (the full scrollable area of the tree).
13096  *
13097  * Since: 2.12
13098  **/
13099 void
13100 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13101                                              gint         wx,
13102                                              gint         wy,
13103                                              gint        *tx,
13104                                              gint        *ty)
13105 {
13106   gint x, y;
13107
13108   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13109
13110   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13111                                                      wx, wy,
13112                                                      &x, &y);
13113   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13114                                                    x, y,
13115                                                    tx, ty);
13116 }
13117
13118 /**
13119  * gtk_tree_view_convert_tree_to_widget_coords:
13120  * @tree_view: a #GtkTreeView
13121  * @tx: X coordinate relative to the tree
13122  * @ty: Y coordinate relative to the tree
13123  * @wx: return location for widget X coordinate
13124  * @wy: return location for widget Y coordinate
13125  *
13126  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13127  * to widget coordinates.
13128  *
13129  * Since: 2.12
13130  **/
13131 void
13132 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13133                                              gint         tx,
13134                                              gint         ty,
13135                                              gint        *wx,
13136                                              gint        *wy)
13137 {
13138   gint x, y;
13139
13140   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13141
13142   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13143                                                    tx, ty,
13144                                                    &x, &y);
13145   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13146                                                      x, y,
13147                                                      wx, wy);
13148 }
13149
13150 /**
13151  * gtk_tree_view_convert_widget_to_bin_window_coords:
13152  * @tree_view: a #GtkTreeView
13153  * @wx: X coordinate relative to the widget
13154  * @wy: Y coordinate relative to the widget
13155  * @bx: return location for bin_window X coordinate
13156  * @by: return location for bin_window Y coordinate
13157  *
13158  * Converts widget coordinates to coordinates for the bin_window
13159  * (see gtk_tree_view_get_bin_window()).
13160  *
13161  * Since: 2.12
13162  **/
13163 void
13164 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13165                                                    gint         wx,
13166                                                    gint         wy,
13167                                                    gint        *bx,
13168                                                    gint        *by)
13169 {
13170   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13171
13172   if (bx)
13173     *bx = wx + tree_view->priv->hadjustment->value;
13174   if (by)
13175     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13176 }
13177
13178 /**
13179  * gtk_tree_view_convert_bin_window_to_widget_coords:
13180  * @tree_view: a #GtkTreeView
13181  * @bx: bin_window X coordinate
13182  * @by: bin_window Y coordinate
13183  * @wx: return location for widget X coordinate
13184  * @wy: return location for widget Y coordinate
13185  *
13186  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13187  * to widget relative coordinates.
13188  *
13189  * Since: 2.12
13190  **/
13191 void
13192 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13193                                                    gint         bx,
13194                                                    gint         by,
13195                                                    gint        *wx,
13196                                                    gint        *wy)
13197 {
13198   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13199
13200   if (wx)
13201     *wx = bx - tree_view->priv->hadjustment->value;
13202   if (wy)
13203     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13204 }
13205
13206 /**
13207  * gtk_tree_view_convert_tree_to_bin_window_coords:
13208  * @tree_view: a #GtkTreeView
13209  * @tx: tree X coordinate
13210  * @ty: tree Y coordinate
13211  * @bx: return location for X coordinate relative to bin_window
13212  * @by: return location for Y coordinate relative to bin_window
13213  *
13214  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13215  * to bin_window coordinates.
13216  *
13217  * Since: 2.12
13218  **/
13219 void
13220 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13221                                                  gint         tx,
13222                                                  gint         ty,
13223                                                  gint        *bx,
13224                                                  gint        *by)
13225 {
13226   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13227
13228   if (bx)
13229     *bx = tx;
13230   if (by)
13231     *by = ty - tree_view->priv->dy;
13232 }
13233
13234 /**
13235  * gtk_tree_view_convert_bin_window_to_tree_coords:
13236  * @tree_view: a #GtkTreeView
13237  * @bx: X coordinate relative to bin_window
13238  * @by: Y coordinate relative to bin_window
13239  * @tx: return location for tree X coordinate
13240  * @ty: return location for tree Y coordinate
13241  *
13242  * Converts bin_window coordinates to coordinates for the
13243  * tree (the full scrollable area of the tree).
13244  *
13245  * Since: 2.12
13246  **/
13247 void
13248 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13249                                                  gint         bx,
13250                                                  gint         by,
13251                                                  gint        *tx,
13252                                                  gint        *ty)
13253 {
13254   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13255
13256   if (tx)
13257     *tx = bx;
13258   if (ty)
13259     *ty = by + tree_view->priv->dy;
13260 }
13261
13262
13263
13264 /**
13265  * gtk_tree_view_get_visible_range:
13266  * @tree_view: A #GtkTreeView
13267  * @start_path: (allow-none): Return location for start of region, or %NULL.
13268  * @end_path: (allow-none): Return location for end of region, or %NULL.
13269  *
13270  * Sets @start_path and @end_path to be the first and last visible path.
13271  * Note that there may be invisible paths in between.
13272  *
13273  * The paths should be freed with gtk_tree_path_free() after use.
13274  *
13275  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13276  *
13277  * Since: 2.8
13278  **/
13279 gboolean
13280 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13281                                  GtkTreePath **start_path,
13282                                  GtkTreePath **end_path)
13283 {
13284   GtkRBTree *tree;
13285   GtkRBNode *node;
13286   gboolean retval;
13287   
13288   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13289
13290   if (!tree_view->priv->tree)
13291     return FALSE;
13292
13293   retval = TRUE;
13294
13295   if (start_path)
13296     {
13297       _gtk_rbtree_find_offset (tree_view->priv->tree,
13298                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13299                                &tree, &node);
13300       if (node)
13301         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13302       else
13303         retval = FALSE;
13304     }
13305
13306   if (end_path)
13307     {
13308       gint y;
13309
13310       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13311         y = tree_view->priv->height - 1;
13312       else
13313         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13314
13315       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13316       if (node)
13317         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13318       else
13319         retval = FALSE;
13320     }
13321
13322   return retval;
13323 }
13324
13325 static void
13326 unset_reorderable (GtkTreeView *tree_view)
13327 {
13328   if (tree_view->priv->reorderable)
13329     {
13330       tree_view->priv->reorderable = FALSE;
13331       g_object_notify (G_OBJECT (tree_view), "reorderable");
13332     }
13333 }
13334
13335 /**
13336  * gtk_tree_view_enable_model_drag_source:
13337  * @tree_view: a #GtkTreeView
13338  * @start_button_mask: Mask of allowed buttons to start drag
13339  * @targets: the table of targets that the drag will support
13340  * @n_targets: the number of items in @targets
13341  * @actions: the bitmask of possible actions for a drag from this
13342  *    widget
13343  *
13344  * Turns @tree_view into a drag source for automatic DND. Calling this
13345  * method sets #GtkTreeView:reorderable to %FALSE.
13346  **/
13347 void
13348 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13349                                         GdkModifierType           start_button_mask,
13350                                         const GtkTargetEntry     *targets,
13351                                         gint                      n_targets,
13352                                         GdkDragAction             actions)
13353 {
13354   TreeViewDragInfo *di;
13355
13356   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13357
13358   gtk_drag_source_set (GTK_WIDGET (tree_view),
13359                        0,
13360                        targets,
13361                        n_targets,
13362                        actions);
13363
13364   di = ensure_info (tree_view);
13365
13366   di->start_button_mask = start_button_mask;
13367   di->source_actions = actions;
13368   di->source_set = TRUE;
13369
13370   unset_reorderable (tree_view);
13371 }
13372
13373 /**
13374  * gtk_tree_view_enable_model_drag_dest:
13375  * @tree_view: a #GtkTreeView
13376  * @targets: the table of targets that the drag will support
13377  * @n_targets: the number of items in @targets
13378  * @actions: the bitmask of possible actions for a drag from this
13379  *    widget
13380  * 
13381  * Turns @tree_view into a drop destination for automatic DND. Calling
13382  * this method sets #GtkTreeView:reorderable to %FALSE.
13383  **/
13384 void
13385 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13386                                       const GtkTargetEntry     *targets,
13387                                       gint                      n_targets,
13388                                       GdkDragAction             actions)
13389 {
13390   TreeViewDragInfo *di;
13391
13392   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13393
13394   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13395                      0,
13396                      targets,
13397                      n_targets,
13398                      actions);
13399
13400   di = ensure_info (tree_view);
13401   di->dest_set = TRUE;
13402
13403   unset_reorderable (tree_view);
13404 }
13405
13406 /**
13407  * gtk_tree_view_unset_rows_drag_source:
13408  * @tree_view: a #GtkTreeView
13409  *
13410  * Undoes the effect of
13411  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13412  * #GtkTreeView:reorderable to %FALSE.
13413  **/
13414 void
13415 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13416 {
13417   TreeViewDragInfo *di;
13418
13419   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13420
13421   di = get_info (tree_view);
13422
13423   if (di)
13424     {
13425       if (di->source_set)
13426         {
13427           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13428           di->source_set = FALSE;
13429         }
13430
13431       if (!di->dest_set && !di->source_set)
13432         remove_info (tree_view);
13433     }
13434   
13435   unset_reorderable (tree_view);
13436 }
13437
13438 /**
13439  * gtk_tree_view_unset_rows_drag_dest:
13440  * @tree_view: a #GtkTreeView
13441  *
13442  * Undoes the effect of
13443  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13444  * #GtkTreeView:reorderable to %FALSE.
13445  **/
13446 void
13447 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13448 {
13449   TreeViewDragInfo *di;
13450
13451   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13452
13453   di = get_info (tree_view);
13454
13455   if (di)
13456     {
13457       if (di->dest_set)
13458         {
13459           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13460           di->dest_set = FALSE;
13461         }
13462
13463       if (!di->dest_set && !di->source_set)
13464         remove_info (tree_view);
13465     }
13466
13467   unset_reorderable (tree_view);
13468 }
13469
13470 /**
13471  * gtk_tree_view_set_drag_dest_row:
13472  * @tree_view: a #GtkTreeView
13473  * @path: (allow-none): The path of the row to highlight, or %NULL.
13474  * @pos: Specifies whether to drop before, after or into the row
13475  * 
13476  * Sets the row that is highlighted for feedback.
13477  **/
13478 void
13479 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13480                                  GtkTreePath            *path,
13481                                  GtkTreeViewDropPosition pos)
13482 {
13483   GtkTreePath *current_dest;
13484
13485   /* Note; this function is exported to allow a custom DND
13486    * implementation, so it can't touch TreeViewDragInfo
13487    */
13488
13489   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13490
13491   current_dest = NULL;
13492
13493   if (tree_view->priv->drag_dest_row)
13494     {
13495       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13496       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13497     }
13498
13499   /* special case a drop on an empty model */
13500   tree_view->priv->empty_view_drop = 0;
13501
13502   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13503       && gtk_tree_path_get_depth (path) == 1
13504       && gtk_tree_path_get_indices (path)[0] == 0)
13505     {
13506       gint n_children;
13507
13508       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13509                                                    NULL);
13510
13511       if (!n_children)
13512         tree_view->priv->empty_view_drop = 1;
13513     }
13514
13515   tree_view->priv->drag_dest_pos = pos;
13516
13517   if (path)
13518     {
13519       tree_view->priv->drag_dest_row =
13520         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13521       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13522     }
13523   else
13524     tree_view->priv->drag_dest_row = NULL;
13525
13526   if (current_dest)
13527     {
13528       GtkRBTree *tree, *new_tree;
13529       GtkRBNode *node, *new_node;
13530
13531       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13532       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13533
13534       if (tree && node)
13535         {
13536           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13537           if (new_tree && new_node)
13538             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13539
13540           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13541           if (new_tree && new_node)
13542             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13543         }
13544       gtk_tree_path_free (current_dest);
13545     }
13546 }
13547
13548 /**
13549  * gtk_tree_view_get_drag_dest_row:
13550  * @tree_view: a #GtkTreeView
13551  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13552  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13553  * 
13554  * Gets information about the row that is highlighted for feedback.
13555  **/
13556 void
13557 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13558                                  GtkTreePath             **path,
13559                                  GtkTreeViewDropPosition  *pos)
13560 {
13561   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13562
13563   if (path)
13564     {
13565       if (tree_view->priv->drag_dest_row)
13566         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13567       else
13568         {
13569           if (tree_view->priv->empty_view_drop)
13570             *path = gtk_tree_path_new_from_indices (0, -1);
13571           else
13572             *path = NULL;
13573         }
13574     }
13575
13576   if (pos)
13577     *pos = tree_view->priv->drag_dest_pos;
13578 }
13579
13580 /**
13581  * gtk_tree_view_get_dest_row_at_pos:
13582  * @tree_view: a #GtkTreeView
13583  * @drag_x: the position to determine the destination row for
13584  * @drag_y: the position to determine the destination row for
13585  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13586  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13587  * 
13588  * Determines the destination row for a given position.  @drag_x and
13589  * @drag_y are expected to be in widget coordinates.  This function is only
13590  * meaningful if @tree_view is realized.  Therefore this function will always
13591  * return %FALSE if @tree_view is not realized or does not have a model.
13592  * 
13593  * Return value: whether there is a row at the given position, %TRUE if this
13594  * is indeed the case.
13595  **/
13596 gboolean
13597 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13598                                    gint                     drag_x,
13599                                    gint                     drag_y,
13600                                    GtkTreePath            **path,
13601                                    GtkTreeViewDropPosition *pos)
13602 {
13603   gint cell_y;
13604   gint bin_x, bin_y;
13605   gdouble offset_into_row;
13606   gdouble third;
13607   GdkRectangle cell;
13608   GtkTreeViewColumn *column = NULL;
13609   GtkTreePath *tmp_path = NULL;
13610
13611   /* Note; this function is exported to allow a custom DND
13612    * implementation, so it can't touch TreeViewDragInfo
13613    */
13614
13615   g_return_val_if_fail (tree_view != NULL, FALSE);
13616   g_return_val_if_fail (drag_x >= 0, FALSE);
13617   g_return_val_if_fail (drag_y >= 0, FALSE);
13618
13619   if (path)
13620     *path = NULL;
13621
13622   if (tree_view->priv->bin_window == NULL)
13623     return FALSE;
13624
13625   if (tree_view->priv->tree == NULL)
13626     return FALSE;
13627
13628   /* If in the top third of a row, we drop before that row; if
13629    * in the bottom third, drop after that row; if in the middle,
13630    * and the row has children, drop into the row.
13631    */
13632   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13633                                                      &bin_x, &bin_y);
13634
13635   if (!gtk_tree_view_get_path_at_pos (tree_view,
13636                                       bin_x,
13637                                       bin_y,
13638                                       &tmp_path,
13639                                       &column,
13640                                       NULL,
13641                                       &cell_y))
13642     return FALSE;
13643
13644   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13645                                      &cell);
13646
13647   offset_into_row = cell_y;
13648
13649   if (path)
13650     *path = tmp_path;
13651   else
13652     gtk_tree_path_free (tmp_path);
13653
13654   tmp_path = NULL;
13655
13656   third = cell.height / 3.0;
13657
13658   if (pos)
13659     {
13660       if (offset_into_row < third)
13661         {
13662           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13663         }
13664       else if (offset_into_row < (cell.height / 2.0))
13665         {
13666           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13667         }
13668       else if (offset_into_row < third * 2.0)
13669         {
13670           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13671         }
13672       else
13673         {
13674           *pos = GTK_TREE_VIEW_DROP_AFTER;
13675         }
13676     }
13677
13678   return TRUE;
13679 }
13680
13681
13682
13683 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13684 /**
13685  * gtk_tree_view_create_row_drag_icon:
13686  * @tree_view: a #GtkTreeView
13687  * @path: a #GtkTreePath in @tree_view
13688  *
13689  * Creates a #cairo_surface_t representation of the row at @path.  
13690  * This image is used for a drag icon.
13691  *
13692  * Return value: (transfer full): a newly-allocated surface of the drag icon.
13693  **/
13694 cairo_surface_t *
13695 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13696                                     GtkTreePath  *path)
13697 {
13698   GtkTreeIter   iter;
13699   GtkRBTree    *tree;
13700   GtkRBNode    *node;
13701   GtkStyle *style;
13702   gint cell_offset;
13703   GList *list;
13704   GdkRectangle background_area;
13705   GtkWidget *widget;
13706   gint depth;
13707   /* start drawing inside the black outline */
13708   gint x = 1, y = 1;
13709   cairo_surface_t *surface;
13710   gint bin_window_width;
13711   gboolean is_separator = FALSE;
13712   gboolean rtl;
13713   cairo_t *cr;
13714
13715   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13716   g_return_val_if_fail (path != NULL, NULL);
13717
13718   widget = GTK_WIDGET (tree_view);
13719
13720   if (!gtk_widget_get_realized (widget))
13721     return NULL;
13722
13723   depth = gtk_tree_path_get_depth (path);
13724
13725   _gtk_tree_view_find_node (tree_view,
13726                             path,
13727                             &tree,
13728                             &node);
13729
13730   if (tree == NULL)
13731     return NULL;
13732
13733   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13734                                 &iter,
13735                                 path))
13736     return NULL;
13737
13738   style = gtk_widget_get_style (widget);
13739
13740   is_separator = row_is_separator (tree_view, &iter, NULL);
13741
13742   cell_offset = x;
13743
13744   background_area.y = y;
13745   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13746
13747   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
13748
13749   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
13750                                                CAIRO_CONTENT_COLOR,
13751                                                bin_window_width + 2,
13752                                                background_area.height + 2);
13753
13754   cr = cairo_create (surface);
13755   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13756   cairo_paint (cr);
13757
13758   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13759
13760   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13761       list;
13762       list = (rtl ? list->prev : list->next))
13763     {
13764       GtkTreeViewColumn *column = list->data;
13765       GdkRectangle cell_area;
13766       gint vertical_separator;
13767
13768       if (!column->visible)
13769         continue;
13770
13771       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13772                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13773                                                node->children?TRUE:FALSE);
13774
13775       background_area.x = cell_offset;
13776       background_area.width = column->width;
13777
13778       gtk_widget_style_get (widget,
13779                             "vertical-separator", &vertical_separator,
13780                             NULL);
13781
13782       cell_area = background_area;
13783
13784       cell_area.y += vertical_separator / 2;
13785       cell_area.height -= vertical_separator;
13786
13787       if (gtk_tree_view_is_expander_column (tree_view, column))
13788         {
13789           if (!rtl)
13790             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13791           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13792
13793           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13794             {
13795               if (!rtl)
13796                 cell_area.x += depth * tree_view->priv->expander_size;
13797               cell_area.width -= depth * tree_view->priv->expander_size;
13798             }
13799         }
13800
13801       if (gtk_tree_view_column_cell_is_visible (column))
13802         {
13803           if (is_separator)
13804             gtk_paint_hline (style,
13805                                    cr,
13806                                    GTK_STATE_NORMAL,
13807                                    widget,
13808                                    NULL,
13809                                    cell_area.x,
13810                                    cell_area.x + cell_area.width,
13811                                    cell_area.y + cell_area.height / 2);
13812           else
13813             _gtk_tree_view_column_cell_render (column,
13814                                                cr,
13815                                                &background_area,
13816                                                &cell_area,
13817                                                0);
13818         }
13819       cell_offset += column->width;
13820     }
13821
13822   cairo_set_source_rgb (cr, 0, 0, 0);
13823   cairo_rectangle (cr, 
13824                    0.5, 0.5, 
13825                    bin_window_width + 1,
13826                    background_area.height + 1);
13827   cairo_set_line_width (cr, 1.0);
13828   cairo_stroke (cr);
13829
13830   cairo_destroy (cr);
13831
13832   cairo_surface_set_device_offset (surface, 2, 2);
13833
13834   return surface;
13835 }
13836
13837
13838 /**
13839  * gtk_tree_view_set_destroy_count_func:
13840  * @tree_view: A #GtkTreeView
13841  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13842  * @data: (allow-none): User data to be passed to @func, or %NULL
13843  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13844  *
13845  * This function should almost never be used.  It is meant for private use by
13846  * ATK for determining the number of visible children that are removed when the
13847  * user collapses a row, or a row is deleted.
13848  **/
13849 void
13850 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13851                                       GtkTreeDestroyCountFunc  func,
13852                                       gpointer                 data,
13853                                       GDestroyNotify           destroy)
13854 {
13855   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13856
13857   if (tree_view->priv->destroy_count_destroy)
13858     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13859
13860   tree_view->priv->destroy_count_func = func;
13861   tree_view->priv->destroy_count_data = data;
13862   tree_view->priv->destroy_count_destroy = destroy;
13863 }
13864
13865
13866 /*
13867  * Interactive search
13868  */
13869
13870 /**
13871  * gtk_tree_view_set_enable_search:
13872  * @tree_view: A #GtkTreeView
13873  * @enable_search: %TRUE, if the user can search interactively
13874  *
13875  * If @enable_search is set, then the user can type in text to search through
13876  * the tree interactively (this is sometimes called "typeahead find").
13877  * 
13878  * Note that even if this is %FALSE, the user can still initiate a search 
13879  * using the "start-interactive-search" key binding.
13880  */
13881 void
13882 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13883                                  gboolean     enable_search)
13884 {
13885   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13886
13887   enable_search = !!enable_search;
13888   
13889   if (tree_view->priv->enable_search != enable_search)
13890     {
13891        tree_view->priv->enable_search = enable_search;
13892        g_object_notify (G_OBJECT (tree_view), "enable-search");
13893     }
13894 }
13895
13896 /**
13897  * gtk_tree_view_get_enable_search:
13898  * @tree_view: A #GtkTreeView
13899  *
13900  * Returns whether or not the tree allows to start interactive searching 
13901  * by typing in text.
13902  *
13903  * Return value: whether or not to let the user search interactively
13904  */
13905 gboolean
13906 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13907 {
13908   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13909
13910   return tree_view->priv->enable_search;
13911 }
13912
13913
13914 /**
13915  * gtk_tree_view_get_search_column:
13916  * @tree_view: A #GtkTreeView
13917  *
13918  * Gets the column searched on by the interactive search code.
13919  *
13920  * Return value: the column the interactive search code searches in.
13921  */
13922 gint
13923 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13924 {
13925   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13926
13927   return (tree_view->priv->search_column);
13928 }
13929
13930 /**
13931  * gtk_tree_view_set_search_column:
13932  * @tree_view: A #GtkTreeView
13933  * @column: the column of the model to search in, or -1 to disable searching
13934  *
13935  * Sets @column as the column where the interactive search code should
13936  * search in for the current model. 
13937  * 
13938  * If the search column is set, users can use the "start-interactive-search"
13939  * key binding to bring up search popup. The enable-search property controls
13940  * whether simply typing text will also start an interactive search.
13941  *
13942  * Note that @column refers to a column of the current model. The search 
13943  * column is reset to -1 when the model is changed.
13944  */
13945 void
13946 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13947                                  gint         column)
13948 {
13949   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13950   g_return_if_fail (column >= -1);
13951
13952   if (tree_view->priv->search_column == column)
13953     return;
13954
13955   tree_view->priv->search_column = column;
13956   g_object_notify (G_OBJECT (tree_view), "search-column");
13957 }
13958
13959 /**
13960  * gtk_tree_view_get_search_equal_func:
13961  * @tree_view: A #GtkTreeView
13962  *
13963  * Returns the compare function currently in use.
13964  *
13965  * Return value: the currently used compare function for the search code.
13966  */
13967
13968 GtkTreeViewSearchEqualFunc
13969 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13970 {
13971   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13972
13973   return tree_view->priv->search_equal_func;
13974 }
13975
13976 /**
13977  * gtk_tree_view_set_search_equal_func:
13978  * @tree_view: A #GtkTreeView
13979  * @search_equal_func: the compare function to use during the search
13980  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
13981  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
13982  *
13983  * Sets the compare function for the interactive search capabilities; note
13984  * that somewhat like strcmp() returning 0 for equality
13985  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
13986  **/
13987 void
13988 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
13989                                      GtkTreeViewSearchEqualFunc  search_equal_func,
13990                                      gpointer                    search_user_data,
13991                                      GDestroyNotify              search_destroy)
13992 {
13993   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13994   g_return_if_fail (search_equal_func != NULL);
13995
13996   if (tree_view->priv->search_destroy)
13997     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
13998
13999   tree_view->priv->search_equal_func = search_equal_func;
14000   tree_view->priv->search_user_data = search_user_data;
14001   tree_view->priv->search_destroy = search_destroy;
14002   if (tree_view->priv->search_equal_func == NULL)
14003     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14004 }
14005
14006 /**
14007  * gtk_tree_view_get_search_entry:
14008  * @tree_view: A #GtkTreeView
14009  *
14010  * Returns the #GtkEntry which is currently in use as interactive search
14011  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14012  * will be returned.
14013  *
14014  * Return value: (transfer none): the entry currently in use as search entry.
14015  *
14016  * Since: 2.10
14017  */
14018 GtkEntry *
14019 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14020 {
14021   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14022
14023   if (tree_view->priv->search_custom_entry_set)
14024     return GTK_ENTRY (tree_view->priv->search_entry);
14025
14026   return NULL;
14027 }
14028
14029 /**
14030  * gtk_tree_view_set_search_entry:
14031  * @tree_view: A #GtkTreeView
14032  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14033  *
14034  * Sets the entry which the interactive search code will use for this
14035  * @tree_view.  This is useful when you want to provide a search entry
14036  * in our interface at all time at a fixed position.  Passing %NULL for
14037  * @entry will make the interactive search code use the built-in popup
14038  * entry again.
14039  *
14040  * Since: 2.10
14041  */
14042 void
14043 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14044                                 GtkEntry    *entry)
14045 {
14046   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14047   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14048
14049   if (tree_view->priv->search_custom_entry_set)
14050     {
14051       if (tree_view->priv->search_entry_changed_id)
14052         {
14053           g_signal_handler_disconnect (tree_view->priv->search_entry,
14054                                        tree_view->priv->search_entry_changed_id);
14055           tree_view->priv->search_entry_changed_id = 0;
14056         }
14057       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14058                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14059                                             tree_view);
14060
14061       g_object_unref (tree_view->priv->search_entry);
14062     }
14063   else if (tree_view->priv->search_window)
14064     {
14065       gtk_widget_destroy (tree_view->priv->search_window);
14066
14067       tree_view->priv->search_window = NULL;
14068     }
14069
14070   if (entry)
14071     {
14072       tree_view->priv->search_entry = g_object_ref (entry);
14073       tree_view->priv->search_custom_entry_set = TRUE;
14074
14075       if (tree_view->priv->search_entry_changed_id == 0)
14076         {
14077           tree_view->priv->search_entry_changed_id =
14078             g_signal_connect (tree_view->priv->search_entry, "changed",
14079                               G_CALLBACK (gtk_tree_view_search_init),
14080                               tree_view);
14081         }
14082       
14083         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14084                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14085                           tree_view);
14086
14087         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14088     }
14089   else
14090     {
14091       tree_view->priv->search_entry = NULL;
14092       tree_view->priv->search_custom_entry_set = FALSE;
14093     }
14094 }
14095
14096 /**
14097  * gtk_tree_view_set_search_position_func:
14098  * @tree_view: A #GtkTreeView
14099  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14100  *    to use the default search position function
14101  * @data: (allow-none): user data to pass to @func, or %NULL
14102  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14103  *
14104  * Sets the function to use when positioning the search dialog.
14105  *
14106  * Since: 2.10
14107  **/
14108 void
14109 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14110                                         GtkTreeViewSearchPositionFunc  func,
14111                                         gpointer                       user_data,
14112                                         GDestroyNotify                 destroy)
14113 {
14114   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14115
14116   if (tree_view->priv->search_position_destroy)
14117     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14118
14119   tree_view->priv->search_position_func = func;
14120   tree_view->priv->search_position_user_data = user_data;
14121   tree_view->priv->search_position_destroy = destroy;
14122   if (tree_view->priv->search_position_func == NULL)
14123     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14124 }
14125
14126 /**
14127  * gtk_tree_view_get_search_position_func:
14128  * @tree_view: A #GtkTreeView
14129  *
14130  * Returns the positioning function currently in use.
14131  *
14132  * Return value: the currently used function for positioning the search dialog.
14133  *
14134  * Since: 2.10
14135  */
14136 GtkTreeViewSearchPositionFunc
14137 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14138 {
14139   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14140
14141   return tree_view->priv->search_position_func;
14142 }
14143
14144
14145 static void
14146 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14147                                   GtkTreeView *tree_view,
14148                                   GdkDevice   *device)
14149 {
14150   if (tree_view->priv->disable_popdown)
14151     return;
14152
14153   if (tree_view->priv->search_entry_changed_id)
14154     {
14155       g_signal_handler_disconnect (tree_view->priv->search_entry,
14156                                    tree_view->priv->search_entry_changed_id);
14157       tree_view->priv->search_entry_changed_id = 0;
14158     }
14159   if (tree_view->priv->typeselect_flush_timeout)
14160     {
14161       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14162       tree_view->priv->typeselect_flush_timeout = 0;
14163     }
14164         
14165   if (gtk_widget_get_visible (search_dialog))
14166     {
14167       /* send focus-in event */
14168       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14169       gtk_widget_hide (search_dialog);
14170       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14171       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14172     }
14173 }
14174
14175 static void
14176 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14177                                     GtkWidget   *search_dialog,
14178                                     gpointer     user_data)
14179 {
14180   gint x, y;
14181   gint tree_x, tree_y;
14182   gint tree_width, tree_height;
14183   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14184   GdkScreen *screen = gdk_window_get_screen (tree_window);
14185   GtkRequisition requisition;
14186   gint monitor_num;
14187   GdkRectangle monitor;
14188
14189   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14190   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14191
14192   gtk_widget_realize (search_dialog);
14193
14194   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14195   tree_width = gdk_window_get_width (tree_window);
14196   tree_height = gdk_window_get_height (tree_window);
14197   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14198
14199   if (tree_x + tree_width > gdk_screen_get_width (screen))
14200     x = gdk_screen_get_width (screen) - requisition.width;
14201   else if (tree_x + tree_width - requisition.width < 0)
14202     x = 0;
14203   else
14204     x = tree_x + tree_width - requisition.width;
14205
14206   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14207     y = gdk_screen_get_height (screen) - requisition.height;
14208   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14209     y = 0;
14210   else
14211     y = tree_y + tree_height;
14212
14213   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14214 }
14215
14216 static void
14217 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14218                                       GtkMenu  *menu,
14219                                       gpointer  data)
14220 {
14221   GtkTreeView *tree_view = (GtkTreeView *)data;
14222
14223   tree_view->priv->disable_popdown = 1;
14224   g_signal_connect (menu, "hide",
14225                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14226 }
14227
14228 /* Because we're visible but offscreen, we just set a flag in the preedit
14229  * callback.
14230  */
14231 static void
14232 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14233                                       GtkTreeView  *tree_view)
14234 {
14235   tree_view->priv->imcontext_changed = 1;
14236   if (tree_view->priv->typeselect_flush_timeout)
14237     {
14238       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14239       tree_view->priv->typeselect_flush_timeout =
14240         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14241                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14242                        tree_view);
14243     }
14244
14245 }
14246
14247 static void
14248 gtk_tree_view_search_activate (GtkEntry    *entry,
14249                                GtkTreeView *tree_view)
14250 {
14251   GtkTreePath *path;
14252   GtkRBNode *node;
14253   GtkRBTree *tree;
14254
14255   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14256                                     tree_view,
14257                                     gtk_get_current_event_device ());
14258
14259   /* If we have a row selected and it's the cursor row, we activate
14260    * the row XXX */
14261   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14262     {
14263       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14264       
14265       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14266       
14267       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14268         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14269       
14270       gtk_tree_path_free (path);
14271     }
14272 }
14273
14274 static gboolean
14275 gtk_tree_view_real_search_enable_popdown (gpointer data)
14276 {
14277   GtkTreeView *tree_view = (GtkTreeView *)data;
14278
14279   tree_view->priv->disable_popdown = 0;
14280
14281   return FALSE;
14282 }
14283
14284 static void
14285 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14286                                      gpointer   data)
14287 {
14288   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14289 }
14290
14291 static gboolean
14292 gtk_tree_view_search_delete_event (GtkWidget *widget,
14293                                    GdkEventAny *event,
14294                                    GtkTreeView *tree_view)
14295 {
14296   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14297
14298   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14299
14300   return TRUE;
14301 }
14302
14303 static gboolean
14304 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14305                                          GdkEventButton *event,
14306                                          GtkTreeView *tree_view)
14307 {
14308   GdkDevice *keyb_device;
14309
14310   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14311
14312   keyb_device = gdk_device_get_associated_device (event->device);
14313   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14314
14315   if (event->window == tree_view->priv->bin_window)
14316     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14317
14318   return TRUE;
14319 }
14320
14321 static gboolean
14322 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14323                                    GdkEventScroll *event,
14324                                    GtkTreeView *tree_view)
14325 {
14326   gboolean retval = FALSE;
14327
14328   if (event->direction == GDK_SCROLL_UP)
14329     {
14330       gtk_tree_view_search_move (widget, tree_view, TRUE);
14331       retval = TRUE;
14332     }
14333   else if (event->direction == GDK_SCROLL_DOWN)
14334     {
14335       gtk_tree_view_search_move (widget, tree_view, FALSE);
14336       retval = TRUE;
14337     }
14338
14339   /* renew the flush timeout */
14340   if (retval && tree_view->priv->typeselect_flush_timeout
14341       && !tree_view->priv->search_custom_entry_set)
14342     {
14343       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14344       tree_view->priv->typeselect_flush_timeout =
14345         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14346                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14347                        tree_view);
14348     }
14349
14350   return retval;
14351 }
14352
14353 static gboolean
14354 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14355                                       GdkEventKey *event,
14356                                       GtkTreeView *tree_view)
14357 {
14358   gboolean retval = FALSE;
14359
14360   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14361   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14362
14363   /* close window and cancel the search */
14364   if (!tree_view->priv->search_custom_entry_set
14365       && (event->keyval == GDK_KEY_Escape ||
14366           event->keyval == GDK_KEY_Tab ||
14367             event->keyval == GDK_KEY_KP_Tab ||
14368             event->keyval == GDK_KEY_ISO_Left_Tab))
14369     {
14370       gtk_tree_view_search_dialog_hide (widget, tree_view,
14371                                         gdk_event_get_device ((GdkEvent *) event));
14372       return TRUE;
14373     }
14374
14375   /* select previous matching iter */
14376   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14377     {
14378       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14379         gtk_widget_error_bell (widget);
14380
14381       retval = TRUE;
14382     }
14383
14384   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14385       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14386     {
14387       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14388         gtk_widget_error_bell (widget);
14389
14390       retval = TRUE;
14391     }
14392
14393   /* select next matching iter */
14394   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14395     {
14396       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14397         gtk_widget_error_bell (widget);
14398
14399       retval = TRUE;
14400     }
14401
14402   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14403       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14404     {
14405       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14406         gtk_widget_error_bell (widget);
14407
14408       retval = TRUE;
14409     }
14410
14411   /* renew the flush timeout */
14412   if (retval && tree_view->priv->typeselect_flush_timeout
14413       && !tree_view->priv->search_custom_entry_set)
14414     {
14415       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14416       tree_view->priv->typeselect_flush_timeout =
14417         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14418                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14419                        tree_view);
14420     }
14421
14422   return retval;
14423 }
14424
14425 /*  this function returns FALSE if there is a search string but
14426  *  nothing was found, and TRUE otherwise.
14427  */
14428 static gboolean
14429 gtk_tree_view_search_move (GtkWidget   *window,
14430                            GtkTreeView *tree_view,
14431                            gboolean     up)
14432 {
14433   gboolean ret;
14434   gint len;
14435   gint count = 0;
14436   const gchar *text;
14437   GtkTreeIter iter;
14438   GtkTreeModel *model;
14439   GtkTreeSelection *selection;
14440
14441   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14442
14443   g_return_val_if_fail (text != NULL, FALSE);
14444
14445   len = strlen (text);
14446
14447   if (up && tree_view->priv->selected_iter == 1)
14448     return strlen (text) < 1;
14449
14450   len = strlen (text);
14451
14452   if (len < 1)
14453     return TRUE;
14454
14455   model = gtk_tree_view_get_model (tree_view);
14456   selection = gtk_tree_view_get_selection (tree_view);
14457
14458   /* search */
14459   gtk_tree_selection_unselect_all (selection);
14460   if (!gtk_tree_model_get_iter_first (model, &iter))
14461     return TRUE;
14462
14463   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14464                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14465
14466   if (ret)
14467     {
14468       /* found */
14469       tree_view->priv->selected_iter += up?(-1):(1);
14470       return TRUE;
14471     }
14472   else
14473     {
14474       /* return to old iter */
14475       count = 0;
14476       gtk_tree_model_get_iter_first (model, &iter);
14477       gtk_tree_view_search_iter (model, selection,
14478                                  &iter, text,
14479                                  &count, tree_view->priv->selected_iter);
14480       return FALSE;
14481     }
14482 }
14483
14484 static gboolean
14485 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14486                                  gint          column,
14487                                  const gchar  *key,
14488                                  GtkTreeIter  *iter,
14489                                  gpointer      search_data)
14490 {
14491   gboolean retval = TRUE;
14492   const gchar *str;
14493   gchar *normalized_string;
14494   gchar *normalized_key;
14495   gchar *case_normalized_string = NULL;
14496   gchar *case_normalized_key = NULL;
14497   GValue value = {0,};
14498   GValue transformed = {0,};
14499
14500   gtk_tree_model_get_value (model, iter, column, &value);
14501
14502   g_value_init (&transformed, G_TYPE_STRING);
14503
14504   if (!g_value_transform (&value, &transformed))
14505     {
14506       g_value_unset (&value);
14507       return TRUE;
14508     }
14509
14510   g_value_unset (&value);
14511
14512   str = g_value_get_string (&transformed);
14513   if (!str)
14514     {
14515       g_value_unset (&transformed);
14516       return TRUE;
14517     }
14518
14519   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14520   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14521
14522   if (normalized_string && normalized_key)
14523     {
14524       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14525       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14526
14527       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14528         retval = FALSE;
14529     }
14530
14531   g_value_unset (&transformed);
14532   g_free (normalized_key);
14533   g_free (normalized_string);
14534   g_free (case_normalized_key);
14535   g_free (case_normalized_string);
14536
14537   return retval;
14538 }
14539
14540 static gboolean
14541 gtk_tree_view_search_iter (GtkTreeModel     *model,
14542                            GtkTreeSelection *selection,
14543                            GtkTreeIter      *iter,
14544                            const gchar      *text,
14545                            gint             *count,
14546                            gint              n)
14547 {
14548   GtkRBTree *tree = NULL;
14549   GtkRBNode *node = NULL;
14550   GtkTreePath *path;
14551
14552   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14553
14554   path = gtk_tree_model_get_path (model, iter);
14555   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14556
14557   do
14558     {
14559       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14560         {
14561           (*count)++;
14562           if (*count == n)
14563             {
14564               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14565                                             TRUE, 0.5, 0.0);
14566               gtk_tree_selection_select_iter (selection, iter);
14567               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14568
14569               if (path)
14570                 gtk_tree_path_free (path);
14571
14572               return TRUE;
14573             }
14574         }
14575
14576       if (node->children)
14577         {
14578           gboolean has_child;
14579           GtkTreeIter tmp;
14580
14581           tree = node->children;
14582           node = tree->root;
14583
14584           while (node->left != tree->nil)
14585             node = node->left;
14586
14587           tmp = *iter;
14588           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14589           gtk_tree_path_down (path);
14590
14591           /* sanity check */
14592           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14593         }
14594       else
14595         {
14596           gboolean done = FALSE;
14597
14598           do
14599             {
14600               node = _gtk_rbtree_next (tree, node);
14601
14602               if (node)
14603                 {
14604                   gboolean has_next;
14605
14606                   has_next = gtk_tree_model_iter_next (model, iter);
14607
14608                   done = TRUE;
14609                   gtk_tree_path_next (path);
14610
14611                   /* sanity check */
14612                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14613                 }
14614               else
14615                 {
14616                   gboolean has_parent;
14617                   GtkTreeIter tmp_iter = *iter;
14618
14619                   node = tree->parent_node;
14620                   tree = tree->parent_tree;
14621
14622                   if (!tree)
14623                     {
14624                       if (path)
14625                         gtk_tree_path_free (path);
14626
14627                       /* we've run out of tree, done with this func */
14628                       return FALSE;
14629                     }
14630
14631                   has_parent = gtk_tree_model_iter_parent (model,
14632                                                            iter,
14633                                                            &tmp_iter);
14634                   gtk_tree_path_up (path);
14635
14636                   /* sanity check */
14637                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14638                 }
14639             }
14640           while (!done);
14641         }
14642     }
14643   while (1);
14644
14645   return FALSE;
14646 }
14647
14648 static void
14649 gtk_tree_view_search_init (GtkWidget   *entry,
14650                            GtkTreeView *tree_view)
14651 {
14652   gint ret;
14653   gint count = 0;
14654   const gchar *text;
14655   GtkTreeIter iter;
14656   GtkTreeModel *model;
14657   GtkTreeSelection *selection;
14658
14659   g_return_if_fail (GTK_IS_ENTRY (entry));
14660   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14661
14662   text = gtk_entry_get_text (GTK_ENTRY (entry));
14663
14664   model = gtk_tree_view_get_model (tree_view);
14665   selection = gtk_tree_view_get_selection (tree_view);
14666
14667   /* search */
14668   gtk_tree_selection_unselect_all (selection);
14669   if (tree_view->priv->typeselect_flush_timeout
14670       && !tree_view->priv->search_custom_entry_set)
14671     {
14672       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14673       tree_view->priv->typeselect_flush_timeout =
14674         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14675                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14676                        tree_view);
14677     }
14678
14679   if (*text == '\0')
14680     return;
14681
14682   if (!gtk_tree_model_get_iter_first (model, &iter))
14683     return;
14684
14685   ret = gtk_tree_view_search_iter (model, selection,
14686                                    &iter, text,
14687                                    &count, 1);
14688
14689   if (ret)
14690     tree_view->priv->selected_iter = 1;
14691 }
14692
14693 static void
14694 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14695                              GtkTreeView     *tree_view)
14696 {
14697   if (tree_view->priv->edited_column == NULL)
14698     return;
14699
14700   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14701   tree_view->priv->edited_column = NULL;
14702
14703   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14704     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14705
14706   g_signal_handlers_disconnect_by_func (cell_editable,
14707                                         gtk_tree_view_remove_widget,
14708                                         tree_view);
14709
14710   gtk_container_remove (GTK_CONTAINER (tree_view),
14711                         GTK_WIDGET (cell_editable));  
14712
14713   /* FIXME should only redraw a single node */
14714   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14715 }
14716
14717 static gboolean
14718 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14719                              GtkTreePath *cursor_path)
14720 {
14721   GtkTreeIter iter;
14722   GdkRectangle background_area;
14723   GdkRectangle cell_area;
14724   GtkCellEditable *editable_widget = NULL;
14725   gchar *path_string;
14726   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14727   gint retval = FALSE;
14728   GtkRBTree *cursor_tree;
14729   GtkRBNode *cursor_node;
14730
14731   g_assert (tree_view->priv->focus_column);
14732
14733   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14734     return FALSE;
14735
14736   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14737       cursor_node == NULL)
14738     return FALSE;
14739
14740   path_string = gtk_tree_path_to_string (cursor_path);
14741   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14742
14743   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14744
14745   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14746                                            tree_view->priv->model,
14747                                            &iter,
14748                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14749                                            cursor_node->children?TRUE:FALSE);
14750   gtk_tree_view_get_background_area (tree_view,
14751                                      cursor_path,
14752                                      tree_view->priv->focus_column,
14753                                      &background_area);
14754   gtk_tree_view_get_cell_area (tree_view,
14755                                cursor_path,
14756                                tree_view->priv->focus_column,
14757                                &cell_area);
14758
14759   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14760                                         &editable_widget,
14761                                         NULL,
14762                                         path_string,
14763                                         &background_area,
14764                                         &cell_area,
14765                                         flags))
14766     {
14767       retval = TRUE;
14768       if (editable_widget != NULL)
14769         {
14770           gint left, right;
14771           GdkRectangle area;
14772           GtkCellRenderer *cell;
14773
14774           area = cell_area;
14775           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14776
14777           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14778
14779           area.x += left;
14780           area.width -= right + left;
14781
14782           gtk_tree_view_real_start_editing (tree_view,
14783                                             tree_view->priv->focus_column,
14784                                             cursor_path,
14785                                             editable_widget,
14786                                             &area,
14787                                             NULL,
14788                                             flags);
14789         }
14790
14791     }
14792   g_free (path_string);
14793   return retval;
14794 }
14795
14796 static void
14797 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14798                                   GtkTreeViewColumn *column,
14799                                   GtkTreePath       *path,
14800                                   GtkCellEditable   *cell_editable,
14801                                   GdkRectangle      *cell_area,
14802                                   GdkEvent          *event,
14803                                   guint              flags)
14804 {
14805   gint pre_val = tree_view->priv->vadjustment->value;
14806   GtkRequisition requisition;
14807
14808   tree_view->priv->edited_column = column;
14809   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14810
14811   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14812   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14813
14814   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
14815                                  &requisition, NULL);
14816
14817   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14818
14819   if (requisition.height < cell_area->height)
14820     {
14821       gint diff = cell_area->height - requisition.height;
14822       gtk_tree_view_put (tree_view,
14823                          GTK_WIDGET (cell_editable),
14824                          cell_area->x, cell_area->y + diff/2,
14825                          cell_area->width, requisition.height);
14826     }
14827   else
14828     {
14829       gtk_tree_view_put (tree_view,
14830                          GTK_WIDGET (cell_editable),
14831                          cell_area->x, cell_area->y,
14832                          cell_area->width, cell_area->height);
14833     }
14834
14835   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14836                                    (GdkEvent *)event);
14837
14838   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14839   g_signal_connect (cell_editable, "remove-widget",
14840                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14841 }
14842
14843 static void
14844 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14845                             gboolean     cancel_editing)
14846 {
14847   GtkTreeViewColumn *column;
14848   GtkCellRenderer *cell;
14849
14850   if (tree_view->priv->edited_column == NULL)
14851     return;
14852
14853   /*
14854    * This is very evil. We need to do this, because
14855    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14856    * later on. If gtk_tree_view_row_changed notices
14857    * tree_view->priv->edited_column != NULL, it'll call
14858    * gtk_tree_view_stop_editing again. Bad things will happen then.
14859    *
14860    * Please read that again if you intend to modify anything here.
14861    */
14862
14863   column = tree_view->priv->edited_column;
14864   tree_view->priv->edited_column = NULL;
14865
14866   cell = _gtk_tree_view_column_get_edited_cell (column);
14867   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14868
14869   if (!cancel_editing)
14870     gtk_cell_editable_editing_done (column->editable_widget);
14871
14872   tree_view->priv->edited_column = column;
14873
14874   gtk_cell_editable_remove_widget (column->editable_widget);
14875 }
14876
14877
14878 /**
14879  * gtk_tree_view_set_hover_selection:
14880  * @tree_view: a #GtkTreeView
14881  * @hover: %TRUE to enable hover selection mode
14882  *
14883  * Enables of disables the hover selection mode of @tree_view.
14884  * Hover selection makes the selected row follow the pointer.
14885  * Currently, this works only for the selection modes 
14886  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14887  * 
14888  * Since: 2.6
14889  **/
14890 void     
14891 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14892                                    gboolean     hover)
14893 {
14894   hover = hover != FALSE;
14895
14896   if (hover != tree_view->priv->hover_selection)
14897     {
14898       tree_view->priv->hover_selection = hover;
14899
14900       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14901     }
14902 }
14903
14904 /**
14905  * gtk_tree_view_get_hover_selection:
14906  * @tree_view: a #GtkTreeView
14907  * 
14908  * Returns whether hover selection mode is turned on for @tree_view.
14909  * 
14910  * Return value: %TRUE if @tree_view is in hover selection mode
14911  *
14912  * Since: 2.6 
14913  **/
14914 gboolean 
14915 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14916 {
14917   return tree_view->priv->hover_selection;
14918 }
14919
14920 /**
14921  * gtk_tree_view_set_hover_expand:
14922  * @tree_view: a #GtkTreeView
14923  * @expand: %TRUE to enable hover selection mode
14924  *
14925  * Enables of disables the hover expansion mode of @tree_view.
14926  * Hover expansion makes rows expand or collapse if the pointer 
14927  * moves over them.
14928  * 
14929  * Since: 2.6
14930  **/
14931 void     
14932 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14933                                 gboolean     expand)
14934 {
14935   expand = expand != FALSE;
14936
14937   if (expand != tree_view->priv->hover_expand)
14938     {
14939       tree_view->priv->hover_expand = expand;
14940
14941       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14942     }
14943 }
14944
14945 /**
14946  * gtk_tree_view_get_hover_expand:
14947  * @tree_view: a #GtkTreeView
14948  * 
14949  * Returns whether hover expansion mode is turned on for @tree_view.
14950  * 
14951  * Return value: %TRUE if @tree_view is in hover expansion mode
14952  *
14953  * Since: 2.6 
14954  **/
14955 gboolean 
14956 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14957 {
14958   return tree_view->priv->hover_expand;
14959 }
14960
14961 /**
14962  * gtk_tree_view_set_rubber_banding:
14963  * @tree_view: a #GtkTreeView
14964  * @enable: %TRUE to enable rubber banding
14965  *
14966  * Enables or disables rubber banding in @tree_view.  If the selection mode
14967  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14968  * multiple rows by dragging the mouse.
14969  * 
14970  * Since: 2.10
14971  **/
14972 void
14973 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14974                                   gboolean     enable)
14975 {
14976   enable = enable != FALSE;
14977
14978   if (enable != tree_view->priv->rubber_banding_enable)
14979     {
14980       tree_view->priv->rubber_banding_enable = enable;
14981
14982       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14983     }
14984 }
14985
14986 /**
14987  * gtk_tree_view_get_rubber_banding:
14988  * @tree_view: a #GtkTreeView
14989  * 
14990  * Returns whether rubber banding is turned on for @tree_view.  If the
14991  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
14992  * user to select multiple rows by dragging the mouse.
14993  * 
14994  * Return value: %TRUE if rubber banding in @tree_view is enabled.
14995  *
14996  * Since: 2.10
14997  **/
14998 gboolean
14999 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15000 {
15001   return tree_view->priv->rubber_banding_enable;
15002 }
15003
15004 /**
15005  * gtk_tree_view_is_rubber_banding_active:
15006  * @tree_view: a #GtkTreeView
15007  * 
15008  * Returns whether a rubber banding operation is currently being done
15009  * in @tree_view.
15010  *
15011  * Return value: %TRUE if a rubber banding operation is currently being
15012  * done in @tree_view.
15013  *
15014  * Since: 2.12
15015  **/
15016 gboolean
15017 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15018 {
15019   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15020
15021   if (tree_view->priv->rubber_banding_enable
15022       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15023     return TRUE;
15024
15025   return FALSE;
15026 }
15027
15028 /**
15029  * gtk_tree_view_get_row_separator_func:
15030  * @tree_view: a #GtkTreeView
15031  * 
15032  * Returns the current row separator function.
15033  * 
15034  * Return value: the current row separator function.
15035  *
15036  * Since: 2.6
15037  **/
15038 GtkTreeViewRowSeparatorFunc 
15039 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15040 {
15041   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15042
15043   return tree_view->priv->row_separator_func;
15044 }
15045
15046 /**
15047  * gtk_tree_view_set_row_separator_func:
15048  * @tree_view: a #GtkTreeView
15049  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15050  * @data: (allow-none): user data to pass to @func, or %NULL
15051  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15052  * 
15053  * Sets the row separator function, which is used to determine
15054  * whether a row should be drawn as a separator. If the row separator
15055  * function is %NULL, no separators are drawn. This is the default value.
15056  *
15057  * Since: 2.6
15058  **/
15059 void
15060 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15061                                       GtkTreeViewRowSeparatorFunc  func,
15062                                       gpointer                     data,
15063                                       GDestroyNotify               destroy)
15064 {
15065   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15066
15067   if (tree_view->priv->row_separator_destroy)
15068     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15069
15070   tree_view->priv->row_separator_func = func;
15071   tree_view->priv->row_separator_data = data;
15072   tree_view->priv->row_separator_destroy = destroy;
15073
15074   /* Have the tree recalculate heights */
15075   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15076   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15077 }
15078
15079   
15080 static void
15081 gtk_tree_view_grab_notify (GtkWidget *widget,
15082                            gboolean   was_grabbed)
15083 {
15084   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15085
15086   tree_view->priv->in_grab = !was_grabbed;
15087
15088   if (!was_grabbed)
15089     {
15090       tree_view->priv->pressed_button = -1;
15091
15092       if (tree_view->priv->rubber_band_status)
15093         gtk_tree_view_stop_rubber_band (tree_view);
15094     }
15095 }
15096
15097 static void
15098 gtk_tree_view_state_changed (GtkWidget      *widget,
15099                              GtkStateType    previous_state)
15100 {
15101   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15102
15103   if (gtk_widget_get_realized (widget))
15104     {
15105       gdk_window_set_background (tree_view->priv->bin_window,
15106                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15107     }
15108
15109   gtk_widget_queue_draw (widget);
15110 }
15111
15112 /**
15113  * gtk_tree_view_get_grid_lines:
15114  * @tree_view: a #GtkTreeView
15115  *
15116  * Returns which grid lines are enabled in @tree_view.
15117  *
15118  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15119  * are enabled.
15120  *
15121  * Since: 2.10
15122  */
15123 GtkTreeViewGridLines
15124 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15125 {
15126   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15127
15128   return tree_view->priv->grid_lines;
15129 }
15130
15131 /**
15132  * gtk_tree_view_set_grid_lines:
15133  * @tree_view: a #GtkTreeView
15134  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15135  * enable.
15136  *
15137  * Sets which grid lines to draw in @tree_view.
15138  *
15139  * Since: 2.10
15140  */
15141 void
15142 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15143                               GtkTreeViewGridLines   grid_lines)
15144 {
15145   GtkTreeViewPrivate *priv;
15146   GtkWidget *widget;
15147   GtkTreeViewGridLines old_grid_lines;
15148
15149   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15150
15151   priv = tree_view->priv;
15152   widget = GTK_WIDGET (tree_view);
15153
15154   old_grid_lines = priv->grid_lines;
15155   priv->grid_lines = grid_lines;
15156   
15157   if (gtk_widget_get_realized (widget))
15158     {
15159       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15160           priv->grid_line_width)
15161         {
15162           priv->grid_line_width = 0;
15163         }
15164       
15165       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15166           !priv->grid_line_width)
15167         {
15168           gint8 *dash_list;
15169
15170           gtk_widget_style_get (widget,
15171                                 "grid-line-width", &priv->grid_line_width,
15172                                 "grid-line-pattern", (gchar *)&dash_list,
15173                                 NULL);
15174       
15175           if (dash_list)
15176             {
15177               priv->grid_line_dashes[0] = dash_list[0];
15178               if (dash_list[0])
15179                 priv->grid_line_dashes[1] = dash_list[1];
15180               
15181               g_free (dash_list);
15182             }
15183           else
15184             {
15185               priv->grid_line_dashes[0] = 1;
15186               priv->grid_line_dashes[1] = 1;
15187             }
15188         }      
15189     }
15190
15191   if (old_grid_lines != grid_lines)
15192     {
15193       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15194       
15195       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15196     }
15197 }
15198
15199 /**
15200  * gtk_tree_view_get_enable_tree_lines:
15201  * @tree_view: a #GtkTreeView.
15202  *
15203  * Returns whether or not tree lines are drawn in @tree_view.
15204  *
15205  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15206  * otherwise.
15207  *
15208  * Since: 2.10
15209  */
15210 gboolean
15211 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15212 {
15213   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15214
15215   return tree_view->priv->tree_lines_enabled;
15216 }
15217
15218 /**
15219  * gtk_tree_view_set_enable_tree_lines:
15220  * @tree_view: a #GtkTreeView
15221  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15222  *
15223  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15224  * This does not have any visible effects for lists.
15225  *
15226  * Since: 2.10
15227  */
15228 void
15229 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15230                                      gboolean     enabled)
15231 {
15232   GtkTreeViewPrivate *priv;
15233   GtkWidget *widget;
15234   gboolean was_enabled;
15235
15236   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15237
15238   enabled = enabled != FALSE;
15239
15240   priv = tree_view->priv;
15241   widget = GTK_WIDGET (tree_view);
15242
15243   was_enabled = priv->tree_lines_enabled;
15244
15245   priv->tree_lines_enabled = enabled;
15246
15247   if (gtk_widget_get_realized (widget))
15248     {
15249       if (!enabled && priv->tree_line_width)
15250         {
15251           priv->tree_line_width = 0;
15252         }
15253       
15254       if (enabled && !priv->tree_line_width)
15255         {
15256           gint8 *dash_list;
15257           gtk_widget_style_get (widget,
15258                                 "tree-line-width", &priv->tree_line_width,
15259                                 "tree-line-pattern", (gchar *)&dash_list,
15260                                 NULL);
15261           
15262           if (dash_list)
15263             {
15264               priv->tree_line_dashes[0] = dash_list[0];
15265               if (dash_list[0])
15266                 priv->tree_line_dashes[1] = dash_list[1];
15267               
15268               g_free (dash_list);
15269             }
15270           else
15271             {
15272               priv->tree_line_dashes[0] = 1;
15273               priv->tree_line_dashes[1] = 1;
15274             }
15275         }
15276     }
15277
15278   if (was_enabled != enabled)
15279     {
15280       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15281
15282       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15283     }
15284 }
15285
15286
15287 /**
15288  * gtk_tree_view_set_show_expanders:
15289  * @tree_view: a #GtkTreeView
15290  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15291  *
15292  * Sets whether to draw and enable expanders and indent child rows in
15293  * @tree_view.  When disabled there will be no expanders visible in trees
15294  * and there will be no way to expand and collapse rows by default.  Also
15295  * note that hiding the expanders will disable the default indentation.  You
15296  * can set a custom indentation in this case using
15297  * gtk_tree_view_set_level_indentation().
15298  * This does not have any visible effects for lists.
15299  *
15300  * Since: 2.12
15301  */
15302 void
15303 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15304                                   gboolean     enabled)
15305 {
15306   gboolean was_enabled;
15307
15308   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15309
15310   enabled = enabled != FALSE;
15311   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15312
15313   if (enabled)
15314     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15315   else
15316     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15317
15318   if (enabled != was_enabled)
15319     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15320 }
15321
15322 /**
15323  * gtk_tree_view_get_show_expanders:
15324  * @tree_view: a #GtkTreeView.
15325  *
15326  * Returns whether or not expanders are drawn in @tree_view.
15327  *
15328  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15329  * otherwise.
15330  *
15331  * Since: 2.12
15332  */
15333 gboolean
15334 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15335 {
15336   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15337
15338   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15339 }
15340
15341 /**
15342  * gtk_tree_view_set_level_indentation:
15343  * @tree_view: a #GtkTreeView
15344  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15345  *
15346  * Sets the amount of extra indentation for child levels to use in @tree_view
15347  * in addition to the default indentation.  The value should be specified in
15348  * pixels, a value of 0 disables this feature and in this case only the default
15349  * indentation will be used.
15350  * This does not have any visible effects for lists.
15351  *
15352  * Since: 2.12
15353  */
15354 void
15355 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15356                                      gint         indentation)
15357 {
15358   tree_view->priv->level_indentation = indentation;
15359
15360   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15361 }
15362
15363 /**
15364  * gtk_tree_view_get_level_indentation:
15365  * @tree_view: a #GtkTreeView.
15366  *
15367  * Returns the amount, in pixels, of extra indentation for child levels
15368  * in @tree_view.
15369  *
15370  * Return value: the amount of extra indentation for child levels in
15371  * @tree_view.  A return value of 0 means that this feature is disabled.
15372  *
15373  * Since: 2.12
15374  */
15375 gint
15376 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15377 {
15378   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15379
15380   return tree_view->priv->level_indentation;
15381 }
15382
15383 /**
15384  * gtk_tree_view_set_tooltip_row:
15385  * @tree_view: a #GtkTreeView
15386  * @tooltip: a #GtkTooltip
15387  * @path: a #GtkTreePath
15388  *
15389  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15390  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15391  * See also gtk_tooltip_set_tip_area().
15392  *
15393  * Since: 2.12
15394  */
15395 void
15396 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15397                                GtkTooltip  *tooltip,
15398                                GtkTreePath *path)
15399 {
15400   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15401   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15402
15403   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15404 }
15405
15406 /**
15407  * gtk_tree_view_set_tooltip_cell:
15408  * @tree_view: a #GtkTreeView
15409  * @tooltip: a #GtkTooltip
15410  * @path: (allow-none): a #GtkTreePath or %NULL
15411  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15412  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15413  *
15414  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15415  * in common.  For example if @path is %NULL and @column is set, the tip
15416  * area will be set to the full area covered by @column.  See also
15417  * gtk_tooltip_set_tip_area().
15418  *
15419  * Note that if @path is not specified and @cell is set and part of a column
15420  * containing the expander, the tooltip might not show and hide at the correct
15421  * position.  In such cases @path must be set to the current node under the
15422  * mouse cursor for this function to operate correctly.
15423  *
15424  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15425  *
15426  * Since: 2.12
15427  */
15428 void
15429 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15430                                 GtkTooltip        *tooltip,
15431                                 GtkTreePath       *path,
15432                                 GtkTreeViewColumn *column,
15433                                 GtkCellRenderer   *cell)
15434 {
15435   GtkAllocation allocation;
15436   GdkRectangle rect;
15437
15438   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15439   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15440   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15441   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15442
15443   /* Determine x values. */
15444   if (column && cell)
15445     {
15446       GdkRectangle tmp;
15447       gint start, width;
15448
15449       /* We always pass in path here, whether it is NULL or not.
15450        * For cells in expander columns path must be specified so that
15451        * we can correctly account for the indentation.  This also means
15452        * that the tooltip is constrained vertically by the "Determine y
15453        * values" code below; this is not a real problem since cells actually
15454        * don't stretch vertically in constrast to columns.
15455        */
15456       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15457       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15458
15459       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15460                                                          tmp.x + start, 0,
15461                                                          &rect.x, NULL);
15462       rect.width = width;
15463     }
15464   else if (column)
15465     {
15466       GdkRectangle tmp;
15467
15468       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15469       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15470                                                          tmp.x, 0,
15471                                                          &rect.x, NULL);
15472       rect.width = tmp.width;
15473     }
15474   else
15475     {
15476       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15477       rect.x = 0;
15478       rect.width = allocation.width;
15479     }
15480
15481   /* Determine y values. */
15482   if (path)
15483     {
15484       GdkRectangle tmp;
15485
15486       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15487       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15488                                                          0, tmp.y,
15489                                                          NULL, &rect.y);
15490       rect.height = tmp.height;
15491     }
15492   else
15493     {
15494       rect.y = 0;
15495       rect.height = tree_view->priv->vadjustment->page_size;
15496     }
15497
15498   gtk_tooltip_set_tip_area (tooltip, &rect);
15499 }
15500
15501 /**
15502  * gtk_tree_view_get_tooltip_context:
15503  * @tree_view: a #GtkTreeView
15504  * @x: the x coordinate (relative to widget coordinates)
15505  * @y: the y coordinate (relative to widget coordinates)
15506  * @keyboard_tip: whether this is a keyboard tooltip or not
15507  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15508  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15509  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15510  *
15511  * This function is supposed to be used in a #GtkWidget::query-tooltip
15512  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15513  * which are received in the signal handler, should be passed to this
15514  * function without modification.
15515  *
15516  * The return value indicates whether there is a tree view row at the given
15517  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15518  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15519  * @model, @path and @iter which have been provided will be set to point to
15520  * that row and the corresponding model.  @x and @y will always be converted
15521  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15522  *
15523  * Return value: whether or not the given tooltip context points to a row.
15524  *
15525  * Since: 2.12
15526  */
15527 gboolean
15528 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15529                                    gint          *x,
15530                                    gint          *y,
15531                                    gboolean       keyboard_tip,
15532                                    GtkTreeModel **model,
15533                                    GtkTreePath  **path,
15534                                    GtkTreeIter   *iter)
15535 {
15536   GtkTreePath *tmppath = NULL;
15537
15538   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15539   g_return_val_if_fail (x != NULL, FALSE);
15540   g_return_val_if_fail (y != NULL, FALSE);
15541
15542   if (keyboard_tip)
15543     {
15544       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15545
15546       if (!tmppath)
15547         return FALSE;
15548     }
15549   else
15550     {
15551       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15552                                                          x, y);
15553
15554       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15555                                           &tmppath, NULL, NULL, NULL))
15556         return FALSE;
15557     }
15558
15559   if (model)
15560     *model = gtk_tree_view_get_model (tree_view);
15561
15562   if (iter)
15563     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15564                              iter, tmppath);
15565
15566   if (path)
15567     *path = tmppath;
15568   else
15569     gtk_tree_path_free (tmppath);
15570
15571   return TRUE;
15572 }
15573
15574 static gboolean
15575 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15576                                     gint        x,
15577                                     gint        y,
15578                                     gboolean    keyboard_tip,
15579                                     GtkTooltip *tooltip,
15580                                     gpointer    data)
15581 {
15582   GValue value = { 0, };
15583   GValue transformed = { 0, };
15584   GtkTreeIter iter;
15585   GtkTreePath *path;
15586   GtkTreeModel *model;
15587   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15588
15589   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15590                                           &x, &y,
15591                                           keyboard_tip,
15592                                           &model, &path, &iter))
15593     return FALSE;
15594
15595   gtk_tree_model_get_value (model, &iter,
15596                             tree_view->priv->tooltip_column, &value);
15597
15598   g_value_init (&transformed, G_TYPE_STRING);
15599
15600   if (!g_value_transform (&value, &transformed))
15601     {
15602       g_value_unset (&value);
15603       gtk_tree_path_free (path);
15604
15605       return FALSE;
15606     }
15607
15608   g_value_unset (&value);
15609
15610   if (!g_value_get_string (&transformed))
15611     {
15612       g_value_unset (&transformed);
15613       gtk_tree_path_free (path);
15614
15615       return FALSE;
15616     }
15617
15618   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15619   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15620
15621   gtk_tree_path_free (path);
15622   g_value_unset (&transformed);
15623
15624   return TRUE;
15625 }
15626
15627 /**
15628  * gtk_tree_view_set_tooltip_column:
15629  * @tree_view: a #GtkTreeView
15630  * @column: an integer, which is a valid column number for @tree_view's model
15631  *
15632  * If you only plan to have simple (text-only) tooltips on full rows, you
15633  * can use this function to have #GtkTreeView handle these automatically
15634  * for you. @column should be set to the column in @tree_view's model
15635  * containing the tooltip texts, or -1 to disable this feature.
15636  *
15637  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15638  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15639  *
15640  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15641  * so &amp;, &lt;, etc have to be escaped in the text.
15642  *
15643  * Since: 2.12
15644  */
15645 void
15646 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15647                                   gint         column)
15648 {
15649   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15650
15651   if (column == tree_view->priv->tooltip_column)
15652     return;
15653
15654   if (column == -1)
15655     {
15656       g_signal_handlers_disconnect_by_func (tree_view,
15657                                             gtk_tree_view_set_tooltip_query_cb,
15658                                             NULL);
15659       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15660     }
15661   else
15662     {
15663       if (tree_view->priv->tooltip_column == -1)
15664         {
15665           g_signal_connect (tree_view, "query-tooltip",
15666                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15667           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15668         }
15669     }
15670
15671   tree_view->priv->tooltip_column = column;
15672   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15673 }
15674
15675 /**
15676  * gtk_tree_view_get_tooltip_column:
15677  * @tree_view: a #GtkTreeView
15678  *
15679  * Returns the column of @tree_view's model which is being used for
15680  * displaying tooltips on @tree_view's rows.
15681  *
15682  * Return value: the index of the tooltip column that is currently being
15683  * used, or -1 if this is disabled.
15684  *
15685  * Since: 2.12
15686  */
15687 gint
15688 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15689 {
15690   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15691
15692   return tree_view->priv->tooltip_column;
15693 }