]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Split off gtkprivate.h
[~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 #include "gtkwidgetprivate.h"
49
50 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
51 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
52 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
53 #define SCROLL_EDGE_SIZE 15
54 #define EXPANDER_EXTRA_PADDING 4
55 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
56 #define AUTO_EXPAND_TIMEOUT 500
57
58 /* The "background" areas of all rows/cells add up to cover the entire tree.
59  * The background includes all inter-row and inter-cell spacing.
60  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
61  * i.e. just the cells, no spacing.
62  */
63
64 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
65 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
66
67 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
68  * vice versa.
69  */
70 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
71 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
72
73 /* This is in bin_window coordinates */
74 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
75 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
76
77 #define ROW_HEIGHT(tree_view,height) \
78   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
79
80
81 typedef struct _GtkTreeViewChild GtkTreeViewChild;
82 struct _GtkTreeViewChild
83 {
84   GtkWidget *widget;
85   gint x;
86   gint y;
87   gint width;
88   gint height;
89 };
90
91
92 typedef struct _TreeViewDragInfo TreeViewDragInfo;
93 struct _TreeViewDragInfo
94 {
95   GdkModifierType start_button_mask;
96   GtkTargetList *_unused_source_target_list;
97   GdkDragAction source_actions;
98
99   GtkTargetList *_unused_dest_target_list;
100
101   guint source_set : 1;
102   guint dest_set : 1;
103 };
104
105
106 /* Signals */
107 enum
108 {
109   ROW_ACTIVATED,
110   TEST_EXPAND_ROW,
111   TEST_COLLAPSE_ROW,
112   ROW_EXPANDED,
113   ROW_COLLAPSED,
114   COLUMNS_CHANGED,
115   CURSOR_CHANGED,
116   MOVE_CURSOR,
117   SELECT_ALL,
118   UNSELECT_ALL,
119   SELECT_CURSOR_ROW,
120   TOGGLE_CURSOR_ROW,
121   EXPAND_COLLAPSE_CURSOR_ROW,
122   SELECT_CURSOR_PARENT,
123   START_INTERACTIVE_SEARCH,
124   LAST_SIGNAL
125 };
126
127 /* Properties */
128 enum {
129   PROP_0,
130   PROP_MODEL,
131   PROP_HADJUSTMENT,
132   PROP_VADJUSTMENT,
133   PROP_HEADERS_VISIBLE,
134   PROP_HEADERS_CLICKABLE,
135   PROP_EXPANDER_COLUMN,
136   PROP_REORDERABLE,
137   PROP_RULES_HINT,
138   PROP_ENABLE_SEARCH,
139   PROP_SEARCH_COLUMN,
140   PROP_FIXED_HEIGHT_MODE,
141   PROP_HOVER_SELECTION,
142   PROP_HOVER_EXPAND,
143   PROP_SHOW_EXPANDERS,
144   PROP_LEVEL_INDENTATION,
145   PROP_RUBBER_BANDING,
146   PROP_ENABLE_GRID_LINES,
147   PROP_ENABLE_TREE_LINES,
148   PROP_TOOLTIP_COLUMN
149 };
150
151 /* object signals */
152 static void     gtk_tree_view_finalize             (GObject          *object);
153 static void     gtk_tree_view_set_property         (GObject         *object,
154                                                     guint            prop_id,
155                                                     const GValue    *value,
156                                                     GParamSpec      *pspec);
157 static void     gtk_tree_view_get_property         (GObject         *object,
158                                                     guint            prop_id,
159                                                     GValue          *value,
160                                                     GParamSpec      *pspec);
161
162 /* gtkwidget signals */
163 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
164 static void     gtk_tree_view_realize              (GtkWidget        *widget);
165 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
166 static void     gtk_tree_view_map                  (GtkWidget        *widget);
167 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
168                                                     GtkRequisition   *requisition);
169 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
170                                                     GtkAllocation    *allocation);
171 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
172                                                     cairo_t          *cr);
173 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
174                                                     GdkEventKey      *event);
175 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
176                                                     GdkEventKey      *event);
177 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
178                                                     GdkEventMotion   *event);
179 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
180                                                     GdkEventCrossing *event);
181 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
182                                                     GdkEventCrossing *event);
183 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
184                                                     GdkEventButton   *event);
185 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
186                                                     GdkEventButton   *event);
187 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
188                                                     GdkEventGrabBroken *event);
189 #if 0
190 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
191                                                     GdkEventConfigure *event);
192 #endif
193
194 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
195                                                     GtkWidget        *child);
196 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
197                                                     GdkEventFocus    *event);
198 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
199                                                     GtkDirectionType  direction);
200 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
201 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
202                                                     GtkStyle         *previous_style);
203 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
204                                                     gboolean          was_grabbed);
205 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
206                                                     GtkStateType      previous_state);
207
208 /* container signals */
209 static void     gtk_tree_view_remove               (GtkContainer     *container,
210                                                     GtkWidget        *widget);
211 static void     gtk_tree_view_forall               (GtkContainer     *container,
212                                                     gboolean          include_internals,
213                                                     GtkCallback       callback,
214                                                     gpointer          callback_data);
215
216 /* Source side drag signals */
217 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
218                                             GdkDragContext   *context);
219 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
220                                             GdkDragContext   *context);
221 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
222                                             GdkDragContext   *context,
223                                             GtkSelectionData *selection_data,
224                                             guint             info,
225                                             guint             time);
226 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
227                                             GdkDragContext   *context);
228
229 /* Target side drag signals */
230 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
231                                                   GdkDragContext   *context,
232                                                   guint             time);
233 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
234                                                   GdkDragContext   *context,
235                                                   gint              x,
236                                                   gint              y,
237                                                   guint             time);
238 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
239                                                   GdkDragContext   *context,
240                                                   gint              x,
241                                                   gint              y,
242                                                   guint             time);
243 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
244                                                   GdkDragContext   *context,
245                                                   gint              x,
246                                                   gint              y,
247                                                   GtkSelectionData *selection_data,
248                                                   guint             info,
249                                                   guint             time);
250
251 /* tree_model signals */
252 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
253                                                            GtkAdjustment   *hadj,
254                                                            GtkAdjustment   *vadj);
255 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
256                                                            GtkMovementStep  step,
257                                                            gint             count);
258 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
259 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
261                                                            gboolean         start_editing);
262 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
263 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
264                                                                gboolean         logical,
265                                                                gboolean         expand,
266                                                                gboolean         open_all);
267 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
268 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
269                                                            GtkTreePath     *path,
270                                                            GtkTreeIter     *iter,
271                                                            gpointer         data);
272 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
273                                                            GtkTreePath     *path,
274                                                            GtkTreeIter     *iter,
275                                                            gpointer         data);
276 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
277                                                            GtkTreePath     *path,
278                                                            GtkTreeIter     *iter,
279                                                            gpointer         data);
280 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
281                                                            GtkTreePath     *path,
282                                                            gpointer         data);
283 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
284                                                            GtkTreePath     *parent,
285                                                            GtkTreeIter     *iter,
286                                                            gint            *new_order,
287                                                            gpointer         data);
288
289 /* Incremental reflow */
290 static gboolean validate_row             (GtkTreeView *tree_view,
291                                           GtkRBTree   *tree,
292                                           GtkRBNode   *node,
293                                           GtkTreeIter *iter,
294                                           GtkTreePath *path);
295 static void     validate_visible_area    (GtkTreeView *tree_view);
296 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
297 static gboolean do_validate_rows         (GtkTreeView *tree_view,
298                                           gboolean     size_request);
299 static gboolean validate_rows            (GtkTreeView *tree_view);
300 static gboolean presize_handler_callback (gpointer     data);
301 static void     install_presize_handler  (GtkTreeView *tree_view);
302 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
303 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
304                                              GtkTreePath *path,
305                                              gint         offset);
306 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
307 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
308 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
309
310 /* Internal functions */
311 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
312                                                               GtkTreeViewColumn  *column);
313 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
314                                                               guint               keyval,
315                                                               guint               modmask,
316                                                               gboolean            add_shifted_binding,
317                                                               GtkMovementStep     step,
318                                                               gint                count);
319 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
320                                                               GtkRBTree          *tree);
321 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
322                                                               GtkTreePath        *path,
323                                                               const GdkRectangle *clip_rect);
324 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
325                                                               GtkRBTree          *tree,
326                                                               GtkRBNode          *node);
327 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
328                                                               cairo_t            *cr,
329                                                               GtkRBTree          *tree,
330                                                               GtkRBNode          *node,
331                                                               gint                x,
332                                                               gint                y);
333 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
334                                                               GtkRBTree          *tree,
335                                                               gint               *x1,
336                                                               gint               *x2);
337 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
338                                                               gint                i,
339                                                               gint               *x);
340 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
341                                                               GtkTreeView        *tree_view);
342 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
343                                                               GtkRBTree          *tree,
344                                                               GtkTreeIter        *iter,
345                                                               gint                depth,
346                                                               gboolean            recurse);
347 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
348                                                               GtkRBTree          *tree,
349                                                               GtkRBNode          *node);
350 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
351                                                               GtkTreeViewColumn  *column,
352                                                               gboolean            focus_to_cell);
353 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
354                                                               GdkEventMotion     *event);
355 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
356 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
357                                                               gint                count);
358 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
359                                                               gint                count);
360 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
361                                                               gint                count);
362 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
363                                                               gint                count);
364 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
365                                                               GtkTreePath        *path,
366                                                               GtkRBTree          *tree,
367                                                               GtkRBNode          *node,
368                                                               gboolean            animate);
369 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
370                                                               GtkTreePath        *path,
371                                                               GtkRBTree          *tree,
372                                                               GtkRBNode          *node,
373                                                               gboolean            open_all,
374                                                               gboolean            animate);
375 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
376                                                               GtkTreePath        *path,
377                                                               gboolean            clear_and_select,
378                                                               gboolean            clamp_node);
379 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
380 static void     column_sizing_notify                         (GObject            *object,
381                                                               GParamSpec         *pspec,
382                                                               gpointer            data);
383 static gboolean expand_collapse_timeout                      (gpointer            data);
384 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
385                                                               GtkRBTree          *tree,
386                                                               GtkRBNode          *node,
387                                                               gboolean            expand);
388 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
389 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
390 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
391 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
392 static void     update_prelight                              (GtkTreeView        *tree_view,
393                                                               int                 x,
394                                                               int                 y);
395
396 /* interactive search */
397 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
398 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
399                                                          GtkTreeView      *tree_view,
400                                                          GdkDevice        *device);
401 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
402                                                          GtkWidget        *search_dialog,
403                                                          gpointer          user_data);
404 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
405                                                          GtkMenu          *menu,
406                                                          gpointer          data);
407 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
408                                                          GtkTreeView      *tree_view);
409 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
410                                                          GtkTreeView      *tree_view);
411 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
412 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
413                                                          gpointer          data);
414 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
415                                                          GdkEventAny      *event,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
418                                                          GdkEventButton   *event,
419                                                          GtkTreeView      *tree_view);
420 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
421                                                          GdkEventScroll   *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
424                                                          GdkEventKey      *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
427                                                          GtkTreeView      *tree_view,
428                                                          gboolean          up);
429 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
430                                                          gint              column,
431                                                          const gchar      *key,
432                                                          GtkTreeIter      *iter,
433                                                          gpointer          search_data);
434 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
435                                                          GtkTreeSelection *selection,
436                                                          GtkTreeIter      *iter,
437                                                          const gchar      *text,
438                                                          gint             *count,
439                                                          gint              n);
440 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
441                                                          GtkTreeView      *tree_view);
442 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
443                                                          GtkWidget        *child_widget,
444                                                          gint              x,
445                                                          gint              y,
446                                                          gint              width,
447                                                          gint              height);
448 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
449                                                          GtkTreePath      *cursor_path);
450 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
451                                               GtkTreeViewColumn *column,
452                                               GtkTreePath       *path,
453                                               GtkCellEditable   *cell_editable,
454                                               GdkRectangle      *cell_area,
455                                               GdkEvent          *event,
456                                               guint              flags);
457 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
458                                                          gboolean     cancel_editing);
459 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
460                                                              GdkDevice   *device,
461                                                              gboolean     keybinding);
462 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
463 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
464                                                          GtkTreeViewColumn *column,
465                                                          gint               drop_position);
466
467 /* GtkBuildable */
468 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
469                                                             GtkBuilder        *builder,
470                                                             GObject           *child,
471                                                             const gchar       *type);
472 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
473                                                             GtkBuilder        *builder,
474                                                             const gchar       *childname);
475 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
476
477
478 static gboolean scroll_row_timeout                   (gpointer     data);
479 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
480 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
481
482 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
483
484 \f
485
486 /* GType Methods
487  */
488
489 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
490                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
491                                                 gtk_tree_view_buildable_init))
492
493 static void
494 gtk_tree_view_class_init (GtkTreeViewClass *class)
495 {
496   GObjectClass *o_class;
497   GtkWidgetClass *widget_class;
498   GtkContainerClass *container_class;
499   GtkBindingSet *binding_set;
500
501   binding_set = gtk_binding_set_by_class (class);
502
503   o_class = (GObjectClass *) class;
504   widget_class = (GtkWidgetClass *) class;
505   container_class = (GtkContainerClass *) class;
506
507   /* GObject signals */
508   o_class->set_property = gtk_tree_view_set_property;
509   o_class->get_property = gtk_tree_view_get_property;
510   o_class->finalize = gtk_tree_view_finalize;
511
512   /* GtkWidget signals */
513   widget_class->destroy = gtk_tree_view_destroy;
514   widget_class->map = gtk_tree_view_map;
515   widget_class->realize = gtk_tree_view_realize;
516   widget_class->unrealize = gtk_tree_view_unrealize;
517   widget_class->size_request = gtk_tree_view_size_request;
518   widget_class->size_allocate = gtk_tree_view_size_allocate;
519   widget_class->button_press_event = gtk_tree_view_button_press;
520   widget_class->button_release_event = gtk_tree_view_button_release;
521   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
522   /*widget_class->configure_event = gtk_tree_view_configure;*/
523   widget_class->motion_notify_event = gtk_tree_view_motion;
524   widget_class->draw = gtk_tree_view_draw;
525   widget_class->key_press_event = gtk_tree_view_key_press;
526   widget_class->key_release_event = gtk_tree_view_key_release;
527   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
528   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
529   widget_class->focus_out_event = gtk_tree_view_focus_out;
530   widget_class->drag_begin = gtk_tree_view_drag_begin;
531   widget_class->drag_end = gtk_tree_view_drag_end;
532   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
533   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
534   widget_class->drag_leave = gtk_tree_view_drag_leave;
535   widget_class->drag_motion = gtk_tree_view_drag_motion;
536   widget_class->drag_drop = gtk_tree_view_drag_drop;
537   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
538   widget_class->focus = gtk_tree_view_focus;
539   widget_class->grab_focus = gtk_tree_view_grab_focus;
540   widget_class->style_set = gtk_tree_view_style_set;
541   widget_class->grab_notify = gtk_tree_view_grab_notify;
542   widget_class->state_changed = gtk_tree_view_state_changed;
543
544   /* GtkContainer signals */
545   container_class->remove = gtk_tree_view_remove;
546   container_class->forall = gtk_tree_view_forall;
547   container_class->set_focus_child = gtk_tree_view_set_focus_child;
548
549   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
550   class->move_cursor = gtk_tree_view_real_move_cursor;
551   class->select_all = gtk_tree_view_real_select_all;
552   class->unselect_all = gtk_tree_view_real_unselect_all;
553   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
554   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
555   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
556   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
557   class->start_interactive_search = gtk_tree_view_start_interactive_search;
558
559   /* Properties */
560
561   g_object_class_install_property (o_class,
562                                    PROP_MODEL,
563                                    g_param_spec_object ("model",
564                                                         P_("TreeView Model"),
565                                                         P_("The model for the tree view"),
566                                                         GTK_TYPE_TREE_MODEL,
567                                                         GTK_PARAM_READWRITE));
568
569   g_object_class_install_property (o_class,
570                                    PROP_HADJUSTMENT,
571                                    g_param_spec_object ("hadjustment",
572                                                         P_("Horizontal Adjustment"),
573                                                         P_("Horizontal Adjustment for the widget"),
574                                                         GTK_TYPE_ADJUSTMENT,
575                                                         GTK_PARAM_READWRITE));
576
577   g_object_class_install_property (o_class,
578                                    PROP_VADJUSTMENT,
579                                    g_param_spec_object ("vadjustment",
580                                                         P_("Vertical Adjustment"),
581                                                         P_("Vertical Adjustment for the widget"),
582                                                         GTK_TYPE_ADJUSTMENT,
583                                                         GTK_PARAM_READWRITE));
584
585   g_object_class_install_property (o_class,
586                                    PROP_HEADERS_VISIBLE,
587                                    g_param_spec_boolean ("headers-visible",
588                                                          P_("Headers Visible"),
589                                                          P_("Show the column header buttons"),
590                                                          TRUE,
591                                                          GTK_PARAM_READWRITE));
592
593   g_object_class_install_property (o_class,
594                                    PROP_HEADERS_CLICKABLE,
595                                    g_param_spec_boolean ("headers-clickable",
596                                                          P_("Headers Clickable"),
597                                                          P_("Column headers respond to click events"),
598                                                          TRUE,
599                                                          GTK_PARAM_READWRITE));
600
601   g_object_class_install_property (o_class,
602                                    PROP_EXPANDER_COLUMN,
603                                    g_param_spec_object ("expander-column",
604                                                         P_("Expander Column"),
605                                                         P_("Set the column for the expander column"),
606                                                         GTK_TYPE_TREE_VIEW_COLUMN,
607                                                         GTK_PARAM_READWRITE));
608
609   g_object_class_install_property (o_class,
610                                    PROP_REORDERABLE,
611                                    g_param_spec_boolean ("reorderable",
612                                                          P_("Reorderable"),
613                                                          P_("View is reorderable"),
614                                                          FALSE,
615                                                          GTK_PARAM_READWRITE));
616
617   g_object_class_install_property (o_class,
618                                    PROP_RULES_HINT,
619                                    g_param_spec_boolean ("rules-hint",
620                                                          P_("Rules Hint"),
621                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
622                                                          FALSE,
623                                                          GTK_PARAM_READWRITE));
624
625     g_object_class_install_property (o_class,
626                                      PROP_ENABLE_SEARCH,
627                                      g_param_spec_boolean ("enable-search",
628                                                            P_("Enable Search"),
629                                                            P_("View allows user to search through columns interactively"),
630                                                            TRUE,
631                                                            GTK_PARAM_READWRITE));
632
633     g_object_class_install_property (o_class,
634                                      PROP_SEARCH_COLUMN,
635                                      g_param_spec_int ("search-column",
636                                                        P_("Search Column"),
637                                                        P_("Model column to search through during interactive search"),
638                                                        -1,
639                                                        G_MAXINT,
640                                                        -1,
641                                                        GTK_PARAM_READWRITE));
642
643     /**
644      * GtkTreeView:fixed-height-mode:
645      *
646      * Setting the ::fixed-height-mode property to %TRUE speeds up 
647      * #GtkTreeView by assuming that all rows have the same height. 
648      * Only enable this option if all rows are the same height.  
649      * Please see gtk_tree_view_set_fixed_height_mode() for more 
650      * information on this option.
651      *
652      * Since: 2.4
653      **/
654     g_object_class_install_property (o_class,
655                                      PROP_FIXED_HEIGHT_MODE,
656                                      g_param_spec_boolean ("fixed-height-mode",
657                                                            P_("Fixed Height Mode"),
658                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
659                                                            FALSE,
660                                                            GTK_PARAM_READWRITE));
661     
662     /**
663      * GtkTreeView:hover-selection:
664      * 
665      * Enables or disables the hover selection mode of @tree_view.
666      * Hover selection makes the selected row follow the pointer.
667      * Currently, this works only for the selection modes 
668      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
669      *
670      * This mode is primarily intended for treeviews in popups, e.g.
671      * in #GtkComboBox or #GtkEntryCompletion.
672      *
673      * Since: 2.6
674      */
675     g_object_class_install_property (o_class,
676                                      PROP_HOVER_SELECTION,
677                                      g_param_spec_boolean ("hover-selection",
678                                                            P_("Hover Selection"),
679                                                            P_("Whether the selection should follow the pointer"),
680                                                            FALSE,
681                                                            GTK_PARAM_READWRITE));
682
683     /**
684      * GtkTreeView:hover-expand:
685      * 
686      * Enables or disables the hover expansion mode of @tree_view.
687      * Hover expansion makes rows expand or collapse if the pointer moves 
688      * over them.
689      *
690      * This mode is primarily intended for treeviews in popups, e.g.
691      * in #GtkComboBox or #GtkEntryCompletion.
692      *
693      * Since: 2.6
694      */
695     g_object_class_install_property (o_class,
696                                      PROP_HOVER_EXPAND,
697                                      g_param_spec_boolean ("hover-expand",
698                                                            P_("Hover Expand"),
699                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
700                                                            FALSE,
701                                                            GTK_PARAM_READWRITE));
702
703     /**
704      * GtkTreeView:show-expanders:
705      *
706      * %TRUE if the view has expanders.
707      *
708      * Since: 2.12
709      */
710     g_object_class_install_property (o_class,
711                                      PROP_SHOW_EXPANDERS,
712                                      g_param_spec_boolean ("show-expanders",
713                                                            P_("Show Expanders"),
714                                                            P_("View has expanders"),
715                                                            TRUE,
716                                                            GTK_PARAM_READWRITE));
717
718     /**
719      * GtkTreeView:level-indentation:
720      *
721      * Extra indentation for each level.
722      *
723      * Since: 2.12
724      */
725     g_object_class_install_property (o_class,
726                                      PROP_LEVEL_INDENTATION,
727                                      g_param_spec_int ("level-indentation",
728                                                        P_("Level Indentation"),
729                                                        P_("Extra indentation for each level"),
730                                                        0,
731                                                        G_MAXINT,
732                                                        0,
733                                                        GTK_PARAM_READWRITE));
734
735     g_object_class_install_property (o_class,
736                                      PROP_RUBBER_BANDING,
737                                      g_param_spec_boolean ("rubber-banding",
738                                                            P_("Rubber Banding"),
739                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
740                                                            FALSE,
741                                                            GTK_PARAM_READWRITE));
742
743     g_object_class_install_property (o_class,
744                                      PROP_ENABLE_GRID_LINES,
745                                      g_param_spec_enum ("enable-grid-lines",
746                                                         P_("Enable Grid Lines"),
747                                                         P_("Whether grid lines should be drawn in the tree view"),
748                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
749                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
750                                                         GTK_PARAM_READWRITE));
751
752     g_object_class_install_property (o_class,
753                                      PROP_ENABLE_TREE_LINES,
754                                      g_param_spec_boolean ("enable-tree-lines",
755                                                            P_("Enable Tree Lines"),
756                                                            P_("Whether tree lines should be drawn in the tree view"),
757                                                            FALSE,
758                                                            GTK_PARAM_READWRITE));
759
760     g_object_class_install_property (o_class,
761                                      PROP_TOOLTIP_COLUMN,
762                                      g_param_spec_int ("tooltip-column",
763                                                        P_("Tooltip Column"),
764                                                        P_("The column in the model containing the tooltip texts for the rows"),
765                                                        -1,
766                                                        G_MAXINT,
767                                                        -1,
768                                                        GTK_PARAM_READWRITE));
769
770   /* Style properties */
771 #define _TREE_VIEW_EXPANDER_SIZE 12
772 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
773 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
774
775   gtk_widget_class_install_style_property (widget_class,
776                                            g_param_spec_int ("expander-size",
777                                                              P_("Expander Size"),
778                                                              P_("Size of the expander arrow"),
779                                                              0,
780                                                              G_MAXINT,
781                                                              _TREE_VIEW_EXPANDER_SIZE,
782                                                              GTK_PARAM_READABLE));
783
784   gtk_widget_class_install_style_property (widget_class,
785                                            g_param_spec_int ("vertical-separator",
786                                                              P_("Vertical Separator Width"),
787                                                              P_("Vertical space between cells.  Must be an even number"),
788                                                              0,
789                                                              G_MAXINT,
790                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
791                                                              GTK_PARAM_READABLE));
792
793   gtk_widget_class_install_style_property (widget_class,
794                                            g_param_spec_int ("horizontal-separator",
795                                                              P_("Horizontal Separator Width"),
796                                                              P_("Horizontal space between cells.  Must be an even number"),
797                                                              0,
798                                                              G_MAXINT,
799                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
800                                                              GTK_PARAM_READABLE));
801
802   gtk_widget_class_install_style_property (widget_class,
803                                            g_param_spec_boolean ("allow-rules",
804                                                                  P_("Allow Rules"),
805                                                                  P_("Allow drawing of alternating color rows"),
806                                                                  TRUE,
807                                                                  GTK_PARAM_READABLE));
808
809   gtk_widget_class_install_style_property (widget_class,
810                                            g_param_spec_boolean ("indent-expanders",
811                                                                  P_("Indent Expanders"),
812                                                                  P_("Make the expanders indented"),
813                                                                  TRUE,
814                                                                  GTK_PARAM_READABLE));
815
816   gtk_widget_class_install_style_property (widget_class,
817                                            g_param_spec_boxed ("even-row-color",
818                                                                P_("Even Row Color"),
819                                                                P_("Color to use for even rows"),
820                                                                GDK_TYPE_COLOR,
821                                                                GTK_PARAM_READABLE));
822
823   gtk_widget_class_install_style_property (widget_class,
824                                            g_param_spec_boxed ("odd-row-color",
825                                                                P_("Odd Row Color"),
826                                                                P_("Color to use for odd rows"),
827                                                                GDK_TYPE_COLOR,
828                                                                GTK_PARAM_READABLE));
829
830   gtk_widget_class_install_style_property (widget_class,
831                                            g_param_spec_int ("grid-line-width",
832                                                              P_("Grid line width"),
833                                                              P_("Width, in pixels, of the tree view grid lines"),
834                                                              0, G_MAXINT, 1,
835                                                              GTK_PARAM_READABLE));
836
837   gtk_widget_class_install_style_property (widget_class,
838                                            g_param_spec_int ("tree-line-width",
839                                                              P_("Tree line width"),
840                                                              P_("Width, in pixels, of the tree view lines"),
841                                                              0, G_MAXINT, 1,
842                                                              GTK_PARAM_READABLE));
843
844   gtk_widget_class_install_style_property (widget_class,
845                                            g_param_spec_string ("grid-line-pattern",
846                                                                 P_("Grid line pattern"),
847                                                                 P_("Dash pattern used to draw the tree view grid lines"),
848                                                                 "\1\1",
849                                                                 GTK_PARAM_READABLE));
850
851   gtk_widget_class_install_style_property (widget_class,
852                                            g_param_spec_string ("tree-line-pattern",
853                                                                 P_("Tree line pattern"),
854                                                                 P_("Dash pattern used to draw the tree view lines"),
855                                                                 "\1\1",
856                                                                 GTK_PARAM_READABLE));
857
858   /* Signals */
859   /**
860    * GtkTreeView::set-scroll-adjustments
861    * @horizontal: the horizontal #GtkAdjustment
862    * @vertical: the vertical #GtkAdjustment
863    *
864    * Set the scroll adjustments for the tree view. Usually scrolled containers
865    * like #GtkScrolledWindow will emit this signal to connect two instances
866    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
867    */
868   widget_class->set_scroll_adjustments_signal =
869     g_signal_new (I_("set-scroll-adjustments"),
870                   G_TYPE_FROM_CLASS (o_class),
871                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
872                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
873                   NULL, NULL,
874                   _gtk_marshal_VOID__OBJECT_OBJECT,
875                   G_TYPE_NONE, 2,
876                   GTK_TYPE_ADJUSTMENT,
877                   GTK_TYPE_ADJUSTMENT);
878
879   /**
880    * GtkTreeView::row-activated:
881    * @tree_view: the object on which the signal is emitted
882    * @path: the #GtkTreePath for the activated row
883    * @column: the #GtkTreeViewColumn in which the activation occurred
884    *
885    * The "row-activated" signal is emitted when the method
886    * gtk_tree_view_row_activated() is called or the user double clicks 
887    * a treeview row. It is also emitted when a non-editable row is 
888    * selected and one of the keys: Space, Shift+Space, Return or 
889    * Enter is pressed.
890    * 
891    * For selection handling refer to the <link linkend="TreeWidget">tree 
892    * widget conceptual overview</link> as well as #GtkTreeSelection.
893    */
894   tree_view_signals[ROW_ACTIVATED] =
895     g_signal_new (I_("row-activated"),
896                   G_TYPE_FROM_CLASS (o_class),
897                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
898                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
899                   NULL, NULL,
900                   _gtk_marshal_VOID__BOXED_OBJECT,
901                   G_TYPE_NONE, 2,
902                   GTK_TYPE_TREE_PATH,
903                   GTK_TYPE_TREE_VIEW_COLUMN);
904
905   /**
906    * GtkTreeView::test-expand-row:
907    * @tree_view: the object on which the signal is emitted
908    * @iter: the tree iter of the row to expand
909    * @path: a tree path that points to the row 
910    * 
911    * The given row is about to be expanded (show its children nodes). Use this
912    * signal if you need to control the expandability of individual rows.
913    *
914    * Returns: %FALSE to allow expansion, %TRUE to reject
915    */
916   tree_view_signals[TEST_EXPAND_ROW] =
917     g_signal_new (I_("test-expand-row"),
918                   G_TYPE_FROM_CLASS (o_class),
919                   G_SIGNAL_RUN_LAST,
920                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
921                   _gtk_boolean_handled_accumulator, NULL,
922                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
923                   G_TYPE_BOOLEAN, 2,
924                   GTK_TYPE_TREE_ITER,
925                   GTK_TYPE_TREE_PATH);
926
927   /**
928    * GtkTreeView::test-collapse-row:
929    * @tree_view: the object on which the signal is emitted
930    * @iter: the tree iter of the row to collapse
931    * @path: a tree path that points to the row 
932    * 
933    * The given row is about to be collapsed (hide its children nodes). Use this
934    * signal if you need to control the collapsibility of individual rows.
935    *
936    * Returns: %FALSE to allow collapsing, %TRUE to reject
937    */
938   tree_view_signals[TEST_COLLAPSE_ROW] =
939     g_signal_new (I_("test-collapse-row"),
940                   G_TYPE_FROM_CLASS (o_class),
941                   G_SIGNAL_RUN_LAST,
942                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
943                   _gtk_boolean_handled_accumulator, NULL,
944                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
945                   G_TYPE_BOOLEAN, 2,
946                   GTK_TYPE_TREE_ITER,
947                   GTK_TYPE_TREE_PATH);
948
949   /**
950    * GtkTreeView::row-expanded:
951    * @tree_view: the object on which the signal is emitted
952    * @iter: the tree iter of the expanded row
953    * @path: a tree path that points to the row 
954    * 
955    * The given row has been expanded (child nodes are shown).
956    */
957   tree_view_signals[ROW_EXPANDED] =
958     g_signal_new (I_("row-expanded"),
959                   G_TYPE_FROM_CLASS (o_class),
960                   G_SIGNAL_RUN_LAST,
961                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
962                   NULL, NULL,
963                   _gtk_marshal_VOID__BOXED_BOXED,
964                   G_TYPE_NONE, 2,
965                   GTK_TYPE_TREE_ITER,
966                   GTK_TYPE_TREE_PATH);
967
968   /**
969    * GtkTreeView::row-collapsed:
970    * @tree_view: the object on which the signal is emitted
971    * @iter: the tree iter of the collapsed row
972    * @path: a tree path that points to the row 
973    * 
974    * The given row has been collapsed (child nodes are hidden).
975    */
976   tree_view_signals[ROW_COLLAPSED] =
977     g_signal_new (I_("row-collapsed"),
978                   G_TYPE_FROM_CLASS (o_class),
979                   G_SIGNAL_RUN_LAST,
980                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
981                   NULL, NULL,
982                   _gtk_marshal_VOID__BOXED_BOXED,
983                   G_TYPE_NONE, 2,
984                   GTK_TYPE_TREE_ITER,
985                   GTK_TYPE_TREE_PATH);
986
987   /**
988    * GtkTreeView::columns-changed:
989    * @tree_view: the object on which the signal is emitted 
990    * 
991    * The number of columns of the treeview has changed.
992    */
993   tree_view_signals[COLUMNS_CHANGED] =
994     g_signal_new (I_("columns-changed"),
995                   G_TYPE_FROM_CLASS (o_class),
996                   G_SIGNAL_RUN_LAST,
997                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
998                   NULL, NULL,
999                   _gtk_marshal_VOID__VOID,
1000                   G_TYPE_NONE, 0);
1001
1002   /**
1003    * GtkTreeView::cursor-changed:
1004    * @tree_view: the object on which the signal is emitted
1005    * 
1006    * The position of the cursor (focused cell) has changed.
1007    */
1008   tree_view_signals[CURSOR_CHANGED] =
1009     g_signal_new (I_("cursor-changed"),
1010                   G_TYPE_FROM_CLASS (o_class),
1011                   G_SIGNAL_RUN_LAST,
1012                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1013                   NULL, NULL,
1014                   _gtk_marshal_VOID__VOID,
1015                   G_TYPE_NONE, 0);
1016
1017   tree_view_signals[MOVE_CURSOR] =
1018     g_signal_new (I_("move-cursor"),
1019                   G_TYPE_FROM_CLASS (o_class),
1020                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1021                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1022                   NULL, NULL,
1023                   _gtk_marshal_BOOLEAN__ENUM_INT,
1024                   G_TYPE_BOOLEAN, 2,
1025                   GTK_TYPE_MOVEMENT_STEP,
1026                   G_TYPE_INT);
1027
1028   tree_view_signals[SELECT_ALL] =
1029     g_signal_new (I_("select-all"),
1030                   G_TYPE_FROM_CLASS (o_class),
1031                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1032                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1033                   NULL, NULL,
1034                   _gtk_marshal_BOOLEAN__VOID,
1035                   G_TYPE_BOOLEAN, 0);
1036
1037   tree_view_signals[UNSELECT_ALL] =
1038     g_signal_new (I_("unselect-all"),
1039                   G_TYPE_FROM_CLASS (o_class),
1040                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1041                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1042                   NULL, NULL,
1043                   _gtk_marshal_BOOLEAN__VOID,
1044                   G_TYPE_BOOLEAN, 0);
1045
1046   tree_view_signals[SELECT_CURSOR_ROW] =
1047     g_signal_new (I_("select-cursor-row"),
1048                   G_TYPE_FROM_CLASS (o_class),
1049                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1050                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1051                   NULL, NULL,
1052                   _gtk_marshal_BOOLEAN__BOOLEAN,
1053                   G_TYPE_BOOLEAN, 1,
1054                   G_TYPE_BOOLEAN);
1055
1056   tree_view_signals[TOGGLE_CURSOR_ROW] =
1057     g_signal_new (I_("toggle-cursor-row"),
1058                   G_TYPE_FROM_CLASS (o_class),
1059                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1060                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1061                   NULL, NULL,
1062                   _gtk_marshal_BOOLEAN__VOID,
1063                   G_TYPE_BOOLEAN, 0);
1064
1065   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1066     g_signal_new (I_("expand-collapse-cursor-row"),
1067                   G_TYPE_FROM_CLASS (o_class),
1068                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1069                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1070                   NULL, NULL,
1071                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1072                   G_TYPE_BOOLEAN, 3,
1073                   G_TYPE_BOOLEAN,
1074                   G_TYPE_BOOLEAN,
1075                   G_TYPE_BOOLEAN);
1076
1077   tree_view_signals[SELECT_CURSOR_PARENT] =
1078     g_signal_new (I_("select-cursor-parent"),
1079                   G_TYPE_FROM_CLASS (o_class),
1080                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1081                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1082                   NULL, NULL,
1083                   _gtk_marshal_BOOLEAN__VOID,
1084                   G_TYPE_BOOLEAN, 0);
1085
1086   tree_view_signals[START_INTERACTIVE_SEARCH] =
1087     g_signal_new (I_("start-interactive-search"),
1088                   G_TYPE_FROM_CLASS (o_class),
1089                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1090                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1091                   NULL, NULL,
1092                   _gtk_marshal_BOOLEAN__VOID,
1093                   G_TYPE_BOOLEAN, 0);
1094
1095   /* Key bindings */
1096   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1097                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1098   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1099                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1100
1101   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1102                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1103   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1104                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1105
1106   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1107                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1108
1109   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1110                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1111
1112   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1113                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1114   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1115                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1116
1117   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1118                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1119   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1120                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1121
1122   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1123                                   GTK_MOVEMENT_PAGES, -1);
1124   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1125                                   GTK_MOVEMENT_PAGES, -1);
1126
1127   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1128                                   GTK_MOVEMENT_PAGES, 1);
1129   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1130                                   GTK_MOVEMENT_PAGES, 1);
1131
1132
1133   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1134                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1135                                 G_TYPE_INT, 1);
1136
1137   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1138                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1139                                 G_TYPE_INT, -1);
1140
1141   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1142                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1143                                 G_TYPE_INT, 1);
1144
1145   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1146                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1147                                 G_TYPE_INT, -1);
1148
1149   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1150                                 "move-cursor", 2,
1151                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1152                                 G_TYPE_INT, 1);
1153
1154   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1155                                 "move-cursor", 2,
1156                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1157                                 G_TYPE_INT, -1);
1158
1159   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1160                                 "move-cursor", 2,
1161                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1162                                 G_TYPE_INT, 1);
1163
1164   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1165                                 "move-cursor", 2,
1166                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1167                                 G_TYPE_INT, -1);
1168
1169   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1170   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1171
1172   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1173   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1174
1175   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1176   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1177
1178   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1179                                 G_TYPE_BOOLEAN, TRUE);
1180   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1181                                 G_TYPE_BOOLEAN, TRUE);
1182
1183   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1184                                 G_TYPE_BOOLEAN, TRUE);
1185   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1186                                 G_TYPE_BOOLEAN, TRUE);
1187   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1188                                 G_TYPE_BOOLEAN, TRUE);
1189   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1190                                 G_TYPE_BOOLEAN, TRUE);
1191   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193
1194   /* expand and collapse rows */
1195   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1196                                 G_TYPE_BOOLEAN, TRUE,
1197                                 G_TYPE_BOOLEAN, TRUE,
1198                                 G_TYPE_BOOLEAN, FALSE);
1199
1200   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1201                                 "expand-collapse-cursor-row", 3,
1202                                 G_TYPE_BOOLEAN, TRUE,
1203                                 G_TYPE_BOOLEAN, TRUE,
1204                                 G_TYPE_BOOLEAN, TRUE);
1205   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1206                                 "expand-collapse-cursor-row", 3,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE,
1209                                 G_TYPE_BOOLEAN, TRUE);
1210
1211   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1212                                 "expand-collapse-cursor-row", 3,
1213                                 G_TYPE_BOOLEAN, TRUE,
1214                                 G_TYPE_BOOLEAN, FALSE,
1215                                 G_TYPE_BOOLEAN, FALSE);
1216   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1217                                 "expand-collapse-cursor-row", 3,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, FALSE,
1220                                 G_TYPE_BOOLEAN, FALSE);
1221
1222   /* Not doable on US keyboards */
1223   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1224                                 G_TYPE_BOOLEAN, TRUE,
1225                                 G_TYPE_BOOLEAN, TRUE,
1226                                 G_TYPE_BOOLEAN, TRUE);
1227   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1228                                 G_TYPE_BOOLEAN, TRUE,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, FALSE);
1231   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1232                                 G_TYPE_BOOLEAN, TRUE,
1233                                 G_TYPE_BOOLEAN, TRUE,
1234                                 G_TYPE_BOOLEAN, TRUE);
1235   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, TRUE,
1238                                 G_TYPE_BOOLEAN, TRUE);
1239   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1240                                 "expand-collapse-cursor-row", 3,
1241                                 G_TYPE_BOOLEAN, FALSE,
1242                                 G_TYPE_BOOLEAN, TRUE,
1243                                 G_TYPE_BOOLEAN, TRUE);
1244   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1245                                 "expand-collapse-cursor-row", 3,
1246                                 G_TYPE_BOOLEAN, FALSE,
1247                                 G_TYPE_BOOLEAN, TRUE,
1248                                 G_TYPE_BOOLEAN, TRUE);
1249   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1250                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1251                                 "expand-collapse-cursor-row", 3,
1252                                 G_TYPE_BOOLEAN, FALSE,
1253                                 G_TYPE_BOOLEAN, TRUE,
1254                                 G_TYPE_BOOLEAN, TRUE);
1255   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1256                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1257                                 "expand-collapse-cursor-row", 3,
1258                                 G_TYPE_BOOLEAN, FALSE,
1259                                 G_TYPE_BOOLEAN, TRUE,
1260                                 G_TYPE_BOOLEAN, TRUE);
1261
1262   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1263                                 G_TYPE_BOOLEAN, TRUE,
1264                                 G_TYPE_BOOLEAN, FALSE,
1265                                 G_TYPE_BOOLEAN, FALSE);
1266   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1267                                 G_TYPE_BOOLEAN, TRUE,
1268                                 G_TYPE_BOOLEAN, FALSE,
1269                                 G_TYPE_BOOLEAN, TRUE);
1270   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1271                                 G_TYPE_BOOLEAN, TRUE,
1272                                 G_TYPE_BOOLEAN, FALSE,
1273                                 G_TYPE_BOOLEAN, FALSE);
1274   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1275                                 G_TYPE_BOOLEAN, TRUE,
1276                                 G_TYPE_BOOLEAN, FALSE,
1277                                 G_TYPE_BOOLEAN, TRUE);
1278   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1279                                 "expand-collapse-cursor-row", 3,
1280                                 G_TYPE_BOOLEAN, FALSE,
1281                                 G_TYPE_BOOLEAN, FALSE,
1282                                 G_TYPE_BOOLEAN, TRUE);
1283   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1284                                 "expand-collapse-cursor-row", 3,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, FALSE,
1287                                 G_TYPE_BOOLEAN, TRUE);
1288   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1289                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1290                                 "expand-collapse-cursor-row", 3,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, FALSE,
1293                                 G_TYPE_BOOLEAN, TRUE);
1294   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1295                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1296                                 "expand-collapse-cursor-row", 3,
1297                                 G_TYPE_BOOLEAN, FALSE,
1298                                 G_TYPE_BOOLEAN, FALSE,
1299                                 G_TYPE_BOOLEAN, TRUE);
1300
1301   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1302   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1303
1304   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1305
1306   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1307
1308   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1309 }
1310
1311 static void
1312 gtk_tree_view_init (GtkTreeView *tree_view)
1313 {
1314   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1315
1316   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1317   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1318
1319   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1320                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1321                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1322
1323   /* We need some padding */
1324   tree_view->priv->dy = 0;
1325   tree_view->priv->cursor_offset = 0;
1326   tree_view->priv->n_columns = 0;
1327   tree_view->priv->header_height = 1;
1328   tree_view->priv->x_drag = 0;
1329   tree_view->priv->drag_pos = -1;
1330   tree_view->priv->header_has_focus = FALSE;
1331   tree_view->priv->pressed_button = -1;
1332   tree_view->priv->press_start_x = -1;
1333   tree_view->priv->press_start_y = -1;
1334   tree_view->priv->reorderable = FALSE;
1335   tree_view->priv->presize_handler_timer = 0;
1336   tree_view->priv->scroll_sync_timer = 0;
1337   tree_view->priv->fixed_height = -1;
1338   tree_view->priv->fixed_height_mode = FALSE;
1339   tree_view->priv->fixed_height_check = 0;
1340   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1341   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1342   tree_view->priv->enable_search = TRUE;
1343   tree_view->priv->search_column = -1;
1344   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1345   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1346   tree_view->priv->search_custom_entry_set = FALSE;
1347   tree_view->priv->typeselect_flush_timeout = 0;
1348   tree_view->priv->init_hadjust_value = TRUE;    
1349   tree_view->priv->width = 0;
1350           
1351   tree_view->priv->hover_selection = FALSE;
1352   tree_view->priv->hover_expand = FALSE;
1353
1354   tree_view->priv->level_indentation = 0;
1355
1356   tree_view->priv->rubber_banding_enable = FALSE;
1357
1358   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1359   tree_view->priv->tree_lines_enabled = FALSE;
1360
1361   tree_view->priv->tooltip_column = -1;
1362
1363   tree_view->priv->post_validation_flag = FALSE;
1364
1365   tree_view->priv->last_button_x = -1;
1366   tree_view->priv->last_button_y = -1;
1367
1368   tree_view->priv->event_last_x = -10000;
1369   tree_view->priv->event_last_y = -10000;
1370 }
1371
1372 \f
1373
1374 /* GObject Methods
1375  */
1376
1377 static void
1378 gtk_tree_view_set_property (GObject         *object,
1379                             guint            prop_id,
1380                             const GValue    *value,
1381                             GParamSpec      *pspec)
1382 {
1383   GtkTreeView *tree_view;
1384
1385   tree_view = GTK_TREE_VIEW (object);
1386
1387   switch (prop_id)
1388     {
1389     case PROP_MODEL:
1390       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1391       break;
1392     case PROP_HADJUSTMENT:
1393       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1394       break;
1395     case PROP_VADJUSTMENT:
1396       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1397       break;
1398     case PROP_HEADERS_VISIBLE:
1399       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1400       break;
1401     case PROP_HEADERS_CLICKABLE:
1402       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1403       break;
1404     case PROP_EXPANDER_COLUMN:
1405       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1406       break;
1407     case PROP_REORDERABLE:
1408       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1409       break;
1410     case PROP_RULES_HINT:
1411       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1412       break;
1413     case PROP_ENABLE_SEARCH:
1414       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1415       break;
1416     case PROP_SEARCH_COLUMN:
1417       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1418       break;
1419     case PROP_FIXED_HEIGHT_MODE:
1420       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1421       break;
1422     case PROP_HOVER_SELECTION:
1423       tree_view->priv->hover_selection = g_value_get_boolean (value);
1424       break;
1425     case PROP_HOVER_EXPAND:
1426       tree_view->priv->hover_expand = g_value_get_boolean (value);
1427       break;
1428     case PROP_SHOW_EXPANDERS:
1429       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1430       break;
1431     case PROP_LEVEL_INDENTATION:
1432       tree_view->priv->level_indentation = g_value_get_int (value);
1433       break;
1434     case PROP_RUBBER_BANDING:
1435       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1436       break;
1437     case PROP_ENABLE_GRID_LINES:
1438       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1439       break;
1440     case PROP_ENABLE_TREE_LINES:
1441       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1442       break;
1443     case PROP_TOOLTIP_COLUMN:
1444       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1445       break;
1446     default:
1447       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1448       break;
1449     }
1450 }
1451
1452 static void
1453 gtk_tree_view_get_property (GObject    *object,
1454                             guint       prop_id,
1455                             GValue     *value,
1456                             GParamSpec *pspec)
1457 {
1458   GtkTreeView *tree_view;
1459
1460   tree_view = GTK_TREE_VIEW (object);
1461
1462   switch (prop_id)
1463     {
1464     case PROP_MODEL:
1465       g_value_set_object (value, tree_view->priv->model);
1466       break;
1467     case PROP_HADJUSTMENT:
1468       g_value_set_object (value, tree_view->priv->hadjustment);
1469       break;
1470     case PROP_VADJUSTMENT:
1471       g_value_set_object (value, tree_view->priv->vadjustment);
1472       break;
1473     case PROP_HEADERS_VISIBLE:
1474       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1475       break;
1476     case PROP_HEADERS_CLICKABLE:
1477       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1478       break;
1479     case PROP_EXPANDER_COLUMN:
1480       g_value_set_object (value, tree_view->priv->expander_column);
1481       break;
1482     case PROP_REORDERABLE:
1483       g_value_set_boolean (value, tree_view->priv->reorderable);
1484       break;
1485     case PROP_RULES_HINT:
1486       g_value_set_boolean (value, tree_view->priv->has_rules);
1487       break;
1488     case PROP_ENABLE_SEARCH:
1489       g_value_set_boolean (value, tree_view->priv->enable_search);
1490       break;
1491     case PROP_SEARCH_COLUMN:
1492       g_value_set_int (value, tree_view->priv->search_column);
1493       break;
1494     case PROP_FIXED_HEIGHT_MODE:
1495       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1496       break;
1497     case PROP_HOVER_SELECTION:
1498       g_value_set_boolean (value, tree_view->priv->hover_selection);
1499       break;
1500     case PROP_HOVER_EXPAND:
1501       g_value_set_boolean (value, tree_view->priv->hover_expand);
1502       break;
1503     case PROP_SHOW_EXPANDERS:
1504       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1505       break;
1506     case PROP_LEVEL_INDENTATION:
1507       g_value_set_int (value, tree_view->priv->level_indentation);
1508       break;
1509     case PROP_RUBBER_BANDING:
1510       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1511       break;
1512     case PROP_ENABLE_GRID_LINES:
1513       g_value_set_enum (value, tree_view->priv->grid_lines);
1514       break;
1515     case PROP_ENABLE_TREE_LINES:
1516       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1517       break;
1518     case PROP_TOOLTIP_COLUMN:
1519       g_value_set_int (value, tree_view->priv->tooltip_column);
1520       break;
1521     default:
1522       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1523       break;
1524     }
1525 }
1526
1527 static void
1528 gtk_tree_view_finalize (GObject *object)
1529 {
1530   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1531 }
1532
1533
1534 static GtkBuildableIface *parent_buildable_iface;
1535
1536 static void
1537 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1538 {
1539   parent_buildable_iface = g_type_interface_peek_parent (iface);
1540   iface->add_child = gtk_tree_view_buildable_add_child;
1541   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1542 }
1543
1544 static void
1545 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1546                                    GtkBuilder  *builder,
1547                                    GObject     *child,
1548                                    const gchar *type)
1549 {
1550   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1551 }
1552
1553 static GObject *
1554 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1555                                             GtkBuilder        *builder,
1556                                             const gchar       *childname)
1557 {
1558     if (strcmp (childname, "selection") == 0)
1559       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1560     
1561     return parent_buildable_iface->get_internal_child (buildable,
1562                                                        builder,
1563                                                        childname);
1564 }
1565
1566 /* GtkWidget Methods
1567  */
1568
1569 static void
1570 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1571 {
1572   _gtk_rbtree_free (tree_view->priv->tree);
1573   
1574   tree_view->priv->tree = NULL;
1575   tree_view->priv->button_pressed_node = NULL;
1576   tree_view->priv->button_pressed_tree = NULL;
1577   tree_view->priv->prelight_tree = NULL;
1578   tree_view->priv->prelight_node = NULL;
1579   tree_view->priv->expanded_collapsed_node = NULL;
1580   tree_view->priv->expanded_collapsed_tree = NULL;
1581 }
1582
1583 static void
1584 gtk_tree_view_destroy (GtkWidget *widget)
1585 {
1586   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1587   GList *list;
1588
1589   gtk_tree_view_stop_editing (tree_view, TRUE);
1590
1591   if (tree_view->priv->columns != NULL)
1592     {
1593       list = tree_view->priv->columns;
1594       while (list)
1595         {
1596           GtkTreeViewColumn *column;
1597           column = GTK_TREE_VIEW_COLUMN (list->data);
1598           list = list->next;
1599           gtk_tree_view_remove_column (tree_view, column);
1600         }
1601       tree_view->priv->columns = NULL;
1602     }
1603
1604   if (tree_view->priv->tree != NULL)
1605     {
1606       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1607
1608       gtk_tree_view_free_rbtree (tree_view);
1609     }
1610
1611   if (tree_view->priv->selection != NULL)
1612     {
1613       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1614       g_object_unref (tree_view->priv->selection);
1615       tree_view->priv->selection = NULL;
1616     }
1617
1618   if (tree_view->priv->scroll_to_path != NULL)
1619     {
1620       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1621       tree_view->priv->scroll_to_path = NULL;
1622     }
1623
1624   if (tree_view->priv->drag_dest_row != NULL)
1625     {
1626       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1627       tree_view->priv->drag_dest_row = NULL;
1628     }
1629
1630   if (tree_view->priv->top_row != NULL)
1631     {
1632       gtk_tree_row_reference_free (tree_view->priv->top_row);
1633       tree_view->priv->top_row = NULL;
1634     }
1635
1636   if (tree_view->priv->column_drop_func_data &&
1637       tree_view->priv->column_drop_func_data_destroy)
1638     {
1639       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1640       tree_view->priv->column_drop_func_data = NULL;
1641     }
1642
1643   if (tree_view->priv->destroy_count_destroy &&
1644       tree_view->priv->destroy_count_data)
1645     {
1646       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1647       tree_view->priv->destroy_count_data = NULL;
1648     }
1649
1650   gtk_tree_row_reference_free (tree_view->priv->cursor);
1651   tree_view->priv->cursor = NULL;
1652
1653   gtk_tree_row_reference_free (tree_view->priv->anchor);
1654   tree_view->priv->anchor = NULL;
1655
1656   /* destroy interactive search dialog */
1657   if (tree_view->priv->search_window)
1658     {
1659       gtk_widget_destroy (tree_view->priv->search_window);
1660       tree_view->priv->search_window = NULL;
1661       tree_view->priv->search_entry = NULL;
1662       if (tree_view->priv->typeselect_flush_timeout)
1663         {
1664           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1665           tree_view->priv->typeselect_flush_timeout = 0;
1666         }
1667     }
1668
1669   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1670     {
1671       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1672       tree_view->priv->search_user_data = NULL;
1673     }
1674
1675   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1676     {
1677       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1678       tree_view->priv->search_position_user_data = NULL;
1679     }
1680
1681   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1682     {
1683       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1684       tree_view->priv->row_separator_data = NULL;
1685     }
1686   
1687   gtk_tree_view_set_model (tree_view, NULL);
1688
1689   if (tree_view->priv->hadjustment)
1690     {
1691       g_object_unref (tree_view->priv->hadjustment);
1692       tree_view->priv->hadjustment = NULL;
1693     }
1694   if (tree_view->priv->vadjustment)
1695     {
1696       g_object_unref (tree_view->priv->vadjustment);
1697       tree_view->priv->vadjustment = NULL;
1698     }
1699
1700   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
1701 }
1702
1703 /* GtkWidget::map helper */
1704 static void
1705 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1706 {
1707   GList *list;
1708
1709   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1710
1711   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1712     {
1713       GtkTreeViewColumn *column;
1714
1715       for (list = tree_view->priv->columns; list; list = list->next)
1716         {
1717           column = list->data;
1718           if (gtk_widget_get_visible (column->button) &&
1719               !gtk_widget_get_mapped (column->button))
1720             gtk_widget_map (column->button);
1721         }
1722       for (list = tree_view->priv->columns; list; list = list->next)
1723         {
1724           column = list->data;
1725           if (column->visible == FALSE)
1726             continue;
1727           if (column->resizable)
1728             {
1729               gdk_window_raise (column->window);
1730               gdk_window_show (column->window);
1731             }
1732           else
1733             gdk_window_hide (column->window);
1734         }
1735       gdk_window_show (tree_view->priv->header_window);
1736     }
1737 }
1738
1739 static void
1740 gtk_tree_view_map (GtkWidget *widget)
1741 {
1742   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1743   GList *tmp_list;
1744
1745   gtk_widget_set_mapped (widget, TRUE);
1746
1747   tmp_list = tree_view->priv->children;
1748   while (tmp_list)
1749     {
1750       GtkTreeViewChild *child = tmp_list->data;
1751       tmp_list = tmp_list->next;
1752
1753       if (gtk_widget_get_visible (child->widget))
1754         {
1755           if (!gtk_widget_get_mapped (child->widget))
1756             gtk_widget_map (child->widget);
1757         }
1758     }
1759   gdk_window_show (tree_view->priv->bin_window);
1760
1761   gtk_tree_view_map_buttons (tree_view);
1762
1763   gdk_window_show (gtk_widget_get_window (widget));
1764 }
1765
1766 static void
1767 gtk_tree_view_realize (GtkWidget *widget)
1768 {
1769   GtkAllocation allocation;
1770   GtkStyle *style;
1771   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1772   GdkWindow *window;
1773   GdkWindowAttr attributes;
1774   GList *tmp_list;
1775   gint attributes_mask;
1776
1777   gtk_widget_set_realized (widget, TRUE);
1778
1779   gtk_widget_get_allocation (widget, &allocation);
1780
1781   /* Make the main, clipping window */
1782   attributes.window_type = GDK_WINDOW_CHILD;
1783   attributes.x = allocation.x;
1784   attributes.y = allocation.y;
1785   attributes.width = allocation.width;
1786   attributes.height = allocation.height;
1787   attributes.wclass = GDK_INPUT_OUTPUT;
1788   attributes.visual = gtk_widget_get_visual (widget);
1789   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1790
1791   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1792
1793   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1794                            &attributes, attributes_mask);
1795   gtk_widget_set_window (widget, window);
1796   gdk_window_set_user_data (window, widget);
1797
1798   gtk_widget_get_allocation (widget, &allocation);
1799
1800   /* Make the window for the tree */
1801   attributes.x = 0;
1802   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1803   attributes.width = MAX (tree_view->priv->width, allocation.width);
1804   attributes.height = allocation.height;
1805   attributes.event_mask = (GDK_EXPOSURE_MASK |
1806                            GDK_SCROLL_MASK |
1807                            GDK_POINTER_MOTION_MASK |
1808                            GDK_ENTER_NOTIFY_MASK |
1809                            GDK_LEAVE_NOTIFY_MASK |
1810                            GDK_BUTTON_PRESS_MASK |
1811                            GDK_BUTTON_RELEASE_MASK |
1812                            gtk_widget_get_events (widget));
1813
1814   tree_view->priv->bin_window = gdk_window_new (window,
1815                                                 &attributes, attributes_mask);
1816   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1817
1818   gtk_widget_get_allocation (widget, &allocation);
1819
1820   /* Make the column header window */
1821   attributes.x = 0;
1822   attributes.y = 0;
1823   attributes.width = MAX (tree_view->priv->width, allocation.width);
1824   attributes.height = tree_view->priv->header_height;
1825   attributes.event_mask = (GDK_EXPOSURE_MASK |
1826                            GDK_SCROLL_MASK |
1827                            GDK_ENTER_NOTIFY_MASK |
1828                            GDK_LEAVE_NOTIFY_MASK |
1829                            GDK_BUTTON_PRESS_MASK |
1830                            GDK_BUTTON_RELEASE_MASK |
1831                            GDK_KEY_PRESS_MASK |
1832                            GDK_KEY_RELEASE_MASK |
1833                            gtk_widget_get_events (widget));
1834
1835   tree_view->priv->header_window = gdk_window_new (window,
1836                                                    &attributes, attributes_mask);
1837   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1838
1839   /* Add them all up. */
1840   gtk_widget_style_attach (widget);
1841   style = gtk_widget_get_style (widget);
1842   gdk_window_set_background (tree_view->priv->bin_window,
1843                              &style->base[gtk_widget_get_state (widget)]);
1844   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1845
1846   tmp_list = tree_view->priv->children;
1847   while (tmp_list)
1848     {
1849       GtkTreeViewChild *child = tmp_list->data;
1850       tmp_list = tmp_list->next;
1851
1852       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1853     }
1854
1855   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1856     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1857
1858   /* Need to call those here, since they create GCs */
1859   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1860   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1861
1862   install_presize_handler (tree_view); 
1863 }
1864
1865 static void
1866 gtk_tree_view_unrealize (GtkWidget *widget)
1867 {
1868   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1869   GtkTreeViewPrivate *priv = tree_view->priv;
1870   GList *list;
1871
1872   if (priv->scroll_timeout != 0)
1873     {
1874       g_source_remove (priv->scroll_timeout);
1875       priv->scroll_timeout = 0;
1876     }
1877
1878   if (priv->auto_expand_timeout != 0)
1879     {
1880       g_source_remove (priv->auto_expand_timeout);
1881       priv->auto_expand_timeout = 0;
1882     }
1883
1884   if (priv->open_dest_timeout != 0)
1885     {
1886       g_source_remove (priv->open_dest_timeout);
1887       priv->open_dest_timeout = 0;
1888     }
1889
1890   remove_expand_collapse_timeout (tree_view);
1891   
1892   if (priv->presize_handler_timer != 0)
1893     {
1894       g_source_remove (priv->presize_handler_timer);
1895       priv->presize_handler_timer = 0;
1896     }
1897
1898   if (priv->validate_rows_timer != 0)
1899     {
1900       g_source_remove (priv->validate_rows_timer);
1901       priv->validate_rows_timer = 0;
1902     }
1903
1904   if (priv->scroll_sync_timer != 0)
1905     {
1906       g_source_remove (priv->scroll_sync_timer);
1907       priv->scroll_sync_timer = 0;
1908     }
1909
1910   if (priv->typeselect_flush_timeout)
1911     {
1912       g_source_remove (priv->typeselect_flush_timeout);
1913       priv->typeselect_flush_timeout = 0;
1914     }
1915   
1916   for (list = priv->columns; list; list = list->next)
1917     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1918
1919   gdk_window_set_user_data (priv->bin_window, NULL);
1920   gdk_window_destroy (priv->bin_window);
1921   priv->bin_window = NULL;
1922
1923   gdk_window_set_user_data (priv->header_window, NULL);
1924   gdk_window_destroy (priv->header_window);
1925   priv->header_window = NULL;
1926
1927   if (priv->drag_window)
1928     {
1929       gdk_window_set_user_data (priv->drag_window, NULL);
1930       gdk_window_destroy (priv->drag_window);
1931       priv->drag_window = NULL;
1932     }
1933
1934   if (priv->drag_highlight_window)
1935     {
1936       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1937       gdk_window_destroy (priv->drag_highlight_window);
1938       priv->drag_highlight_window = NULL;
1939     }
1940
1941   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1942 }
1943
1944 /* GtkWidget::size_request helper */
1945 static void
1946 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1947 {
1948   GList *list;
1949
1950   tree_view->priv->header_height = 0;
1951
1952   if (tree_view->priv->model)
1953     {
1954       for (list = tree_view->priv->columns; list; list = list->next)
1955         {
1956           GtkRequisition requisition;
1957           GtkTreeViewColumn *column = list->data;
1958
1959           if (column->button == NULL)
1960             continue;
1961
1962           column = list->data;
1963
1964           gtk_widget_get_preferred_size (column->button, &requisition, NULL);
1965           column->button_request = requisition.width;
1966           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1967         }
1968     }
1969 }
1970
1971
1972 /* Called only by ::size_request */
1973 static void
1974 gtk_tree_view_update_size (GtkTreeView *tree_view)
1975 {
1976   GList *list;
1977   GtkTreeViewColumn *column;
1978   gint i;
1979
1980   if (tree_view->priv->model == NULL)
1981     {
1982       tree_view->priv->width = 0;
1983       tree_view->priv->prev_width = 0;                   
1984       tree_view->priv->height = 0;
1985       return;
1986     }
1987
1988   tree_view->priv->prev_width = tree_view->priv->width;  
1989   tree_view->priv->width = 0;
1990
1991   /* keep this in sync with size_allocate below */
1992   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1993     {
1994       gint real_requested_width = 0;
1995       column = list->data;
1996       if (!column->visible)
1997         continue;
1998
1999       if (column->use_resized_width)
2000         {
2001           real_requested_width = column->resized_width;
2002         }
2003       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2004         {
2005           real_requested_width = column->fixed_width;
2006         }
2007       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2008         {
2009           real_requested_width = MAX (column->requested_width, column->button_request);
2010         }
2011       else
2012         {
2013           real_requested_width = column->requested_width;
2014         }
2015
2016       if (column->min_width != -1)
2017         real_requested_width = MAX (real_requested_width, column->min_width);
2018       if (column->max_width != -1)
2019         real_requested_width = MIN (real_requested_width, column->max_width);
2020
2021       tree_view->priv->width += real_requested_width;
2022     }
2023
2024   if (tree_view->priv->tree == NULL)
2025     tree_view->priv->height = 0;
2026   else
2027     tree_view->priv->height = tree_view->priv->tree->root->offset;
2028 }
2029
2030 static void
2031 gtk_tree_view_size_request (GtkWidget      *widget,
2032                             GtkRequisition *requisition)
2033 {
2034   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2035   GList *tmp_list;
2036
2037   /* we validate some rows initially just to make sure we have some size. 
2038    * In practice, with a lot of static lists, this should get a good width.
2039    */
2040   do_validate_rows (tree_view, FALSE);
2041   gtk_tree_view_size_request_columns (tree_view);
2042   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2043
2044   requisition->width = tree_view->priv->width;
2045   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2046
2047   tmp_list = tree_view->priv->children;
2048
2049   while (tmp_list)
2050     {
2051       GtkTreeViewChild *child = tmp_list->data;
2052       GtkRequisition child_requisition;
2053
2054       tmp_list = tmp_list->next;
2055
2056       if (gtk_widget_get_visible (child->widget))
2057         gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
2058     }
2059 }
2060
2061 static int
2062 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2063 {
2064   int width = 0;
2065   GList *list;
2066   gboolean rtl;
2067
2068   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2069   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2070        list->data != tree_view->priv->expander_column;
2071        list = (rtl ? list->prev : list->next))
2072     {
2073       GtkTreeViewColumn *column = list->data;
2074
2075       width += column->width;
2076     }
2077
2078   return width;
2079 }
2080
2081 static void
2082 invalidate_column (GtkTreeView       *tree_view,
2083                    GtkTreeViewColumn *column)
2084 {
2085   gint column_offset = 0;
2086   GList *list;
2087   GtkWidget *widget = GTK_WIDGET (tree_view);
2088   gboolean rtl;
2089
2090   if (!gtk_widget_get_realized (widget))
2091     return;
2092
2093   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2094   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2095        list;
2096        list = (rtl ? list->prev : list->next))
2097     {
2098       GtkTreeViewColumn *tmpcolumn = list->data;
2099       if (tmpcolumn == column)
2100         {
2101           GtkAllocation allocation;
2102           GdkRectangle invalid_rect;
2103
2104           gtk_widget_get_allocation (widget, &allocation);
2105           invalid_rect.x = column_offset;
2106           invalid_rect.y = 0;
2107           invalid_rect.width = column->width;
2108           invalid_rect.height = allocation.height;
2109
2110           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2111           break;
2112         }
2113       
2114       column_offset += tmpcolumn->width;
2115     }
2116 }
2117
2118 static void
2119 invalidate_last_column (GtkTreeView *tree_view)
2120 {
2121   GList *last_column;
2122   gboolean rtl;
2123
2124   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2125
2126   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2127        last_column;
2128        last_column = (rtl ? last_column->next : last_column->prev))
2129     {
2130       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2131         {
2132           invalidate_column (tree_view, last_column->data);
2133           return;
2134         }
2135     }
2136 }
2137
2138 static gint
2139 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2140                                                     GtkTreeViewColumn *column)
2141 {
2142   gint real_requested_width;
2143
2144   if (column->use_resized_width)
2145     {
2146       real_requested_width = column->resized_width;
2147     }
2148   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2149     {
2150       real_requested_width = column->fixed_width;
2151     }
2152   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2153     {
2154       real_requested_width = MAX (column->requested_width, column->button_request);
2155     }
2156   else
2157     {
2158       real_requested_width = column->requested_width;
2159       if (real_requested_width < 0)
2160         real_requested_width = 0;
2161     }
2162
2163   if (column->min_width != -1)
2164     real_requested_width = MAX (real_requested_width, column->min_width);
2165   if (column->max_width != -1)
2166     real_requested_width = MIN (real_requested_width, column->max_width);
2167
2168   return real_requested_width;
2169 }
2170
2171 /* GtkWidget::size_allocate helper */
2172 static void
2173 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2174                                      gboolean  *width_changed)
2175 {
2176   GtkTreeView *tree_view;
2177   GList *list, *first_column, *last_column;
2178   GtkTreeViewColumn *column;
2179   GtkAllocation allocation;
2180   GtkAllocation widget_allocation;
2181   gint width = 0;
2182   gint extra, extra_per_column, extra_for_last;
2183   gint full_requested_width = 0;
2184   gint number_of_expand_columns = 0;
2185   gboolean column_changed = FALSE;
2186   gboolean rtl;
2187   gboolean update_expand;
2188   
2189   tree_view = GTK_TREE_VIEW (widget);
2190
2191   for (last_column = g_list_last (tree_view->priv->columns);
2192        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2193        last_column = last_column->prev)
2194     ;
2195   if (last_column == NULL)
2196     return;
2197
2198   for (first_column = g_list_first (tree_view->priv->columns);
2199        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2200        first_column = first_column->next)
2201     ;
2202
2203   allocation.y = 0;
2204   allocation.height = tree_view->priv->header_height;
2205
2206   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2207
2208   /* find out how many extra space and expandable columns we have */
2209   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2210     {
2211       column = (GtkTreeViewColumn *)list->data;
2212
2213       if (!column->visible)
2214         continue;
2215
2216       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2217
2218       if (column->expand)
2219         number_of_expand_columns++;
2220     }
2221
2222   /* Only update the expand value if the width of the widget has changed,
2223    * or the number of expand columns has changed, or if there are no expand
2224    * columns, or if we didn't have an size-allocation yet after the
2225    * last validated node.
2226    */
2227   update_expand = (width_changed && *width_changed == TRUE)
2228       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2229       || number_of_expand_columns == 0
2230       || tree_view->priv->post_validation_flag == TRUE;
2231
2232   tree_view->priv->post_validation_flag = FALSE;
2233
2234   gtk_widget_get_allocation (widget, &widget_allocation);
2235   if (!update_expand)
2236     {
2237       extra = tree_view->priv->last_extra_space;
2238       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2239     }
2240   else
2241     {
2242       extra = MAX (widget_allocation.width - full_requested_width, 0);
2243       extra_for_last = 0;
2244
2245       tree_view->priv->last_extra_space = extra;
2246     }
2247
2248   if (number_of_expand_columns > 0)
2249     extra_per_column = extra/number_of_expand_columns;
2250   else
2251     extra_per_column = 0;
2252
2253   if (update_expand)
2254     {
2255       tree_view->priv->last_extra_space_per_column = extra_per_column;
2256       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2257     }
2258
2259   for (list = (rtl ? last_column : first_column); 
2260        list != (rtl ? first_column->prev : last_column->next);
2261        list = (rtl ? list->prev : list->next)) 
2262     {
2263       gint real_requested_width = 0;
2264       gint old_width;
2265
2266       column = list->data;
2267       old_width = column->width;
2268
2269       if (!column->visible)
2270         continue;
2271
2272       /* We need to handle the dragged button specially.
2273        */
2274       if (column == tree_view->priv->drag_column)
2275         {
2276           GtkAllocation drag_allocation;
2277
2278           drag_allocation.x = 0;
2279           drag_allocation.y = 0;
2280           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2281           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2282           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2283                                     &drag_allocation);
2284           width += drag_allocation.width;
2285           continue;
2286         }
2287
2288       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2289
2290       allocation.x = width;
2291       column->width = real_requested_width;
2292
2293       if (column->expand)
2294         {
2295           if (number_of_expand_columns == 1)
2296             {
2297               /* We add the remander to the last column as
2298                * */
2299               column->width += extra;
2300             }
2301           else
2302             {
2303               column->width += extra_per_column;
2304               extra -= extra_per_column;
2305               number_of_expand_columns --;
2306             }
2307         }
2308       else if (number_of_expand_columns == 0 &&
2309                list == last_column)
2310         {
2311           column->width += extra;
2312         }
2313
2314       /* In addition to expand, the last column can get even more
2315        * extra space so all available space is filled up.
2316        */
2317       if (extra_for_last > 0 && list == last_column)
2318         column->width += extra_for_last;
2319
2320       g_object_notify (G_OBJECT (column), "width");
2321
2322       allocation.width = column->width;
2323       width += column->width;
2324
2325       if (column->width > old_width)
2326         column_changed = TRUE;
2327
2328       gtk_widget_size_allocate (column->button, &allocation);
2329
2330       if (column->window)
2331         gdk_window_move_resize (column->window,
2332                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2333                                 allocation.y,
2334                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2335     }
2336
2337   /* We change the width here.  The user might have been resizing columns,
2338    * so the total width of the tree view changes.
2339    */
2340   tree_view->priv->width = width;
2341   if (width_changed)
2342     *width_changed = TRUE;
2343
2344   if (column_changed)
2345     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2346 }
2347
2348
2349 static void
2350 gtk_tree_view_size_allocate (GtkWidget     *widget,
2351                              GtkAllocation *allocation)
2352 {
2353   GtkAllocation widget_allocation;
2354   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2355   GList *tmp_list;
2356   gboolean width_changed = FALSE;
2357   gint old_width;
2358
2359   gtk_widget_get_allocation (widget, &widget_allocation);
2360   old_width = widget_allocation.width;
2361   if (allocation->width != widget_allocation.width)
2362     width_changed = TRUE;
2363
2364   gtk_widget_set_allocation (widget, allocation);
2365
2366   tmp_list = tree_view->priv->children;
2367
2368   while (tmp_list)
2369     {
2370       GtkAllocation allocation;
2371
2372       GtkTreeViewChild *child = tmp_list->data;
2373       tmp_list = tmp_list->next;
2374
2375       /* totally ignore our child's requisition */
2376       allocation.x = child->x;
2377       allocation.y = child->y;
2378       allocation.width = child->width;
2379       allocation.height = child->height;
2380       gtk_widget_size_allocate (child->widget, &allocation);
2381     }
2382
2383   /* We size-allocate the columns first because the width of the
2384    * tree view (used in updating the adjustments below) might change.
2385    */
2386   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2387
2388   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2389   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2390                                 allocation->width);
2391   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2392                                      allocation->width * 0.9);
2393   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2394                                      allocation->width * 0.1);
2395   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2396   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2397                             MAX (tree_view->priv->hadjustment->page_size,
2398                                  tree_view->priv->width));
2399   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2400
2401   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2402     {
2403       if (allocation->width < tree_view->priv->width)
2404         {
2405           if (tree_view->priv->init_hadjust_value)
2406             {
2407               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2408                                         MAX (tree_view->priv->width -
2409                                              allocation->width, 0));
2410               tree_view->priv->init_hadjust_value = FALSE;
2411             }
2412           else if (allocation->width != old_width)
2413             {
2414               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2415                                         CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width,
2416                                                0,
2417                                                tree_view->priv->width - allocation->width));
2418             }
2419           else
2420             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2421                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value),
2422                                              0,
2423                                              tree_view->priv->width - allocation->width));
2424         }
2425       else
2426         {
2427           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2428           tree_view->priv->init_hadjust_value = TRUE;
2429         }
2430     }
2431   else
2432     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2433       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2434                                 MAX (tree_view->priv->width -
2435                                      allocation->width, 0));
2436
2437   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2438   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2439                                 allocation->height -
2440                                 TREE_VIEW_HEADER_HEIGHT (tree_view));
2441   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2442                                      tree_view->priv->vadjustment->page_size * 0.1);
2443   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2444                                      tree_view->priv->vadjustment->page_size * 0.9);
2445   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2446   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2447                             MAX (tree_view->priv->vadjustment->page_size,
2448                                  tree_view->priv->height));
2449   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2450
2451   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2452   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2453     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2454   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2455     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2456                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2457   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2458     gtk_tree_view_top_row_to_dy (tree_view);
2459   else
2460     gtk_tree_view_dy_to_top_row (tree_view);
2461   
2462   if (gtk_widget_get_realized (widget))
2463     {
2464       gdk_window_move_resize (gtk_widget_get_window (widget),
2465                               allocation->x, allocation->y,
2466                               allocation->width, allocation->height);
2467       gdk_window_move_resize (tree_view->priv->header_window,
2468                               - (gint) tree_view->priv->hadjustment->value,
2469                               0,
2470                               MAX (tree_view->priv->width, allocation->width),
2471                               tree_view->priv->header_height);
2472       gdk_window_move_resize (tree_view->priv->bin_window,
2473                               - (gint) tree_view->priv->hadjustment->value,
2474                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2475                               MAX (tree_view->priv->width, allocation->width),
2476                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2477     }
2478
2479   if (tree_view->priv->tree == NULL)
2480     invalidate_empty_focus (tree_view);
2481
2482   if (gtk_widget_get_realized (widget))
2483     {
2484       gboolean has_expand_column = FALSE;
2485       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2486         {
2487           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2488             {
2489               has_expand_column = TRUE;
2490               break;
2491             }
2492         }
2493
2494       if (width_changed && tree_view->priv->expander_column)
2495         {
2496           /* Might seem awkward, but is the best heuristic I could come up
2497            * with.  Only if the width of the columns before the expander
2498            * changes, we will update the prelight status.  It is this
2499            * width that makes the expander move vertically.  Always updating
2500            * prelight status causes trouble with hover selections.
2501            */
2502           gint width_before_expander;
2503
2504           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2505
2506           if (tree_view->priv->prev_width_before_expander
2507               != width_before_expander)
2508               update_prelight (tree_view,
2509                                tree_view->priv->event_last_x,
2510                                tree_view->priv->event_last_y);
2511
2512           tree_view->priv->prev_width_before_expander = width_before_expander;
2513         }
2514
2515       /* This little hack only works if we have an LTR locale, and no column has the  */
2516       if (width_changed)
2517         {
2518           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2519               ! has_expand_column)
2520             invalidate_last_column (tree_view);
2521           else
2522             gtk_widget_queue_draw (widget);
2523         }
2524     }
2525 }
2526
2527 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2528 static void
2529 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2530 {
2531   GtkWidget *widget = GTK_WIDGET (tree_view);
2532
2533   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2534     gtk_widget_grab_focus (widget);
2535   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2536 }
2537
2538 static inline gboolean
2539 row_is_separator (GtkTreeView *tree_view,
2540                   GtkTreeIter *iter,
2541                   GtkTreePath *path)
2542 {
2543   gboolean is_separator = FALSE;
2544
2545   if (tree_view->priv->row_separator_func)
2546     {
2547       GtkTreeIter tmpiter;
2548
2549       if (iter)
2550         tmpiter = *iter;
2551       else
2552         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2553
2554       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2555                                                           &tmpiter,
2556                                                           tree_view->priv->row_separator_data);
2557     }
2558
2559   return is_separator;
2560 }
2561
2562 static gboolean
2563 gtk_tree_view_button_press (GtkWidget      *widget,
2564                             GdkEventButton *event)
2565 {
2566   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2567   GList *list;
2568   GtkTreeViewColumn *column = NULL;
2569   gint i;
2570   GdkRectangle background_area;
2571   GdkRectangle cell_area;
2572   gint vertical_separator;
2573   gint horizontal_separator;
2574   gboolean path_is_selectable;
2575   gboolean rtl;
2576
2577   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2578   gtk_tree_view_stop_editing (tree_view, FALSE);
2579   gtk_widget_style_get (widget,
2580                         "vertical-separator", &vertical_separator,
2581                         "horizontal-separator", &horizontal_separator,
2582                         NULL);
2583
2584
2585   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2586    * we're done handling the button press.
2587    */
2588
2589   if (event->window == tree_view->priv->bin_window)
2590     {
2591       GtkRBNode *node;
2592       GtkRBTree *tree;
2593       GtkTreePath *path;
2594       gchar *path_string;
2595       gint depth;
2596       gint new_y;
2597       gint y_offset;
2598       gint dval;
2599       gint pre_val, aft_val;
2600       GtkTreeViewColumn *column = NULL;
2601       GtkCellRenderer *focus_cell = NULL;
2602       gint column_handled_click = FALSE;
2603       gboolean row_double_click = FALSE;
2604       gboolean rtl;
2605       gboolean node_selected;
2606
2607       /* Empty tree? */
2608       if (tree_view->priv->tree == NULL)
2609         {
2610           grab_focus_and_unset_draw_keyfocus (tree_view);
2611           return TRUE;
2612         }
2613
2614       /* are we in an arrow? */
2615       if (tree_view->priv->prelight_node &&
2616           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2617           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2618         {
2619           if (event->button == 1)
2620             {
2621               gtk_grab_add (widget);
2622               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2623               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2624               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2625                                               tree_view->priv->prelight_tree,
2626                                               tree_view->priv->prelight_node);
2627             }
2628
2629           grab_focus_and_unset_draw_keyfocus (tree_view);
2630           return TRUE;
2631         }
2632
2633       /* find the node that was clicked */
2634       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2635       if (new_y < 0)
2636         new_y = 0;
2637       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2638
2639       if (node == NULL)
2640         {
2641           /* We clicked in dead space */
2642           grab_focus_and_unset_draw_keyfocus (tree_view);
2643           return TRUE;
2644         }
2645
2646       /* Get the path and the node */
2647       path = _gtk_tree_view_find_path (tree_view, tree, node);
2648       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2649
2650       if (!path_is_selectable)
2651         {
2652           gtk_tree_path_free (path);
2653           grab_focus_and_unset_draw_keyfocus (tree_view);
2654           return TRUE;
2655         }
2656
2657       depth = gtk_tree_path_get_depth (path);
2658       background_area.y = y_offset + event->y;
2659       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2660       background_area.x = 0;
2661
2662
2663       /* Let the column have a chance at selecting it. */
2664       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2665       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2666            list; list = (rtl ? list->prev : list->next))
2667         {
2668           GtkTreeViewColumn *candidate = list->data;
2669
2670           if (!candidate->visible)
2671             continue;
2672
2673           background_area.width = candidate->width;
2674           if ((background_area.x > (gint) event->x) ||
2675               (background_area.x + background_area.width <= (gint) event->x))
2676             {
2677               background_area.x += background_area.width;
2678               continue;
2679             }
2680
2681           /* we found the focus column */
2682           column = candidate;
2683           cell_area = background_area;
2684           cell_area.width -= horizontal_separator;
2685           cell_area.height -= vertical_separator;
2686           cell_area.x += horizontal_separator/2;
2687           cell_area.y += vertical_separator/2;
2688           if (gtk_tree_view_is_expander_column (tree_view, column))
2689             {
2690               if (!rtl)
2691                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2692               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2693
2694               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2695                 {
2696                   if (!rtl)
2697                     cell_area.x += depth * tree_view->priv->expander_size;
2698                   cell_area.width -= depth * tree_view->priv->expander_size;
2699                 }
2700             }
2701           break;
2702         }
2703
2704       if (column == NULL)
2705         {
2706           gtk_tree_path_free (path);
2707           grab_focus_and_unset_draw_keyfocus (tree_view);
2708           return FALSE;
2709         }
2710
2711       tree_view->priv->focus_column = column;
2712
2713       /* decide if we edit */
2714       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2715           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2716         {
2717           GtkTreePath *anchor;
2718           GtkTreeIter iter;
2719
2720           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2721           gtk_tree_view_column_cell_set_cell_data (column,
2722                                                    tree_view->priv->model,
2723                                                    &iter,
2724                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2725                                                    node->children?TRUE:FALSE);
2726
2727           if (tree_view->priv->anchor)
2728             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2729           else
2730             anchor = NULL;
2731
2732           if ((anchor && !gtk_tree_path_compare (anchor, path))
2733               || !_gtk_tree_view_column_has_editable_cell (column))
2734             {
2735               GtkCellEditable *cell_editable = NULL;
2736
2737               /* FIXME: get the right flags */
2738               guint flags = 0;
2739
2740               path_string = gtk_tree_path_to_string (path);
2741
2742               if (_gtk_tree_view_column_cell_event (column,
2743                                                     &cell_editable,
2744                                                     (GdkEvent *)event,
2745                                                     path_string,
2746                                                     &background_area,
2747                                                     &cell_area, flags))
2748                 {
2749                   if (cell_editable != NULL)
2750                     {
2751                       gint left, right;
2752                       GdkRectangle area;
2753
2754                       area = cell_area;
2755                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2756
2757                       area.x += left;
2758                       area.width -= right + left;
2759
2760                       gtk_tree_view_real_start_editing (tree_view,
2761                                                         column,
2762                                                         path,
2763                                                         cell_editable,
2764                                                         &area,
2765                                                         (GdkEvent *)event,
2766                                                         flags);
2767                       g_free (path_string);
2768                       gtk_tree_path_free (path);
2769                       gtk_tree_path_free (anchor);
2770                       return TRUE;
2771                     }
2772                   column_handled_click = TRUE;
2773                 }
2774               g_free (path_string);
2775             }
2776           if (anchor)
2777             gtk_tree_path_free (anchor);
2778         }
2779
2780       /* select */
2781       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2782       pre_val = tree_view->priv->vadjustment->value;
2783
2784       /* we only handle selection modifications on the first button press
2785        */
2786       if (event->type == GDK_BUTTON_PRESS)
2787         {
2788           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2789             tree_view->priv->ctrl_pressed = TRUE;
2790           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2791             tree_view->priv->shift_pressed = TRUE;
2792
2793           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2794           if (focus_cell)
2795             gtk_tree_view_column_focus_cell (column, focus_cell);
2796
2797           if (event->state & GDK_CONTROL_MASK)
2798             {
2799               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2800               gtk_tree_view_real_toggle_cursor_row (tree_view);
2801             }
2802           else if (event->state & GDK_SHIFT_MASK)
2803             {
2804               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2805               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2806             }
2807           else
2808             {
2809               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2810             }
2811
2812           tree_view->priv->ctrl_pressed = FALSE;
2813           tree_view->priv->shift_pressed = FALSE;
2814         }
2815
2816       /* the treeview may have been scrolled because of _set_cursor,
2817        * correct here
2818        */
2819
2820       aft_val = tree_view->priv->vadjustment->value;
2821       dval = pre_val - aft_val;
2822
2823       cell_area.y += dval;
2824       background_area.y += dval;
2825
2826       /* Save press to possibly begin a drag
2827        */
2828       if (!column_handled_click &&
2829           !tree_view->priv->in_grab &&
2830           tree_view->priv->pressed_button < 0)
2831         {
2832           tree_view->priv->pressed_button = event->button;
2833           tree_view->priv->press_start_x = event->x;
2834           tree_view->priv->press_start_y = event->y;
2835
2836           if (tree_view->priv->rubber_banding_enable
2837               && !node_selected
2838               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2839             {
2840               tree_view->priv->press_start_y += tree_view->priv->dy;
2841               tree_view->priv->rubber_band_x = event->x;
2842               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2843               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2844
2845               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2846                 tree_view->priv->rubber_band_ctrl = TRUE;
2847               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2848                 tree_view->priv->rubber_band_shift = TRUE;
2849             }
2850         }
2851
2852       /* Test if a double click happened on the same row. */
2853       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2854         {
2855           int double_click_time, double_click_distance;
2856
2857           g_object_get (gtk_settings_get_default (),
2858                         "gtk-double-click-time", &double_click_time,
2859                         "gtk-double-click-distance", &double_click_distance,
2860                         NULL);
2861
2862           /* Same conditions as _gdk_event_button_generate */
2863           if (tree_view->priv->last_button_x != -1 &&
2864               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2865               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2866               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2867             {
2868               /* We do no longer compare paths of this row and the
2869                * row clicked previously.  We use the double click
2870                * distance to decide whether this is a valid click,
2871                * allowing the mouse to slightly move over another row.
2872                */
2873               row_double_click = TRUE;
2874
2875               tree_view->priv->last_button_time = 0;
2876               tree_view->priv->last_button_x = -1;
2877               tree_view->priv->last_button_y = -1;
2878             }
2879           else
2880             {
2881               tree_view->priv->last_button_time = event->time;
2882               tree_view->priv->last_button_x = event->x;
2883               tree_view->priv->last_button_y = event->y;
2884             }
2885         }
2886
2887       if (row_double_click)
2888         {
2889           gtk_grab_remove (widget);
2890           gtk_tree_view_row_activated (tree_view, path, column);
2891
2892           if (tree_view->priv->pressed_button == event->button)
2893             tree_view->priv->pressed_button = -1;
2894         }
2895
2896       gtk_tree_path_free (path);
2897
2898       /* If we activated the row through a double click we don't want to grab
2899        * focus back, as moving focus to another widget is pretty common.
2900        */
2901       if (!row_double_click)
2902         grab_focus_and_unset_draw_keyfocus (tree_view);
2903
2904       return TRUE;
2905     }
2906
2907   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2908    */
2909   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2910     {
2911       column = list->data;
2912       if (event->window == column->window &&
2913           column->resizable &&
2914           column->window)
2915         {
2916           GtkAllocation button_allocation;
2917           gpointer drag_data;
2918
2919           if (event->type == GDK_2BUTTON_PRESS &&
2920               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2921             {
2922               column->use_resized_width = FALSE;
2923               _gtk_tree_view_column_autosize (tree_view, column);
2924               return TRUE;
2925             }
2926
2927           if (gdk_pointer_grab (column->window, FALSE,
2928                                 GDK_POINTER_MOTION_HINT_MASK |
2929                                 GDK_BUTTON1_MOTION_MASK |
2930                                 GDK_BUTTON_RELEASE_MASK,
2931                                 NULL, NULL, event->time))
2932             return FALSE;
2933
2934           gtk_grab_add (widget);
2935           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2936           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2937
2938           /* block attached dnd signal handler */
2939           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2940           if (drag_data)
2941             g_signal_handlers_block_matched (widget,
2942                                              G_SIGNAL_MATCH_DATA,
2943                                              0, 0, NULL, NULL,
2944                                              drag_data);
2945
2946           gtk_widget_get_allocation (column->button, &button_allocation);
2947           tree_view->priv->drag_pos = i;
2948           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
2949
2950           if (!gtk_widget_has_focus (widget))
2951             gtk_widget_grab_focus (widget);
2952
2953           return TRUE;
2954         }
2955     }
2956   return FALSE;
2957 }
2958
2959 /* GtkWidget::button_release_event helper */
2960 static gboolean
2961 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2962                                           GdkEventButton *event)
2963 {
2964   GtkTreeView *tree_view;
2965   GList *l;
2966   gboolean rtl;
2967
2968   tree_view = GTK_TREE_VIEW (widget);
2969
2970   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2971   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2972   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2973
2974   /* Move the button back */
2975   g_object_ref (tree_view->priv->drag_column->button);
2976   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2977   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2978   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2979   g_object_unref (tree_view->priv->drag_column->button);
2980   gtk_widget_queue_resize (widget);
2981   if (tree_view->priv->drag_column->resizable)
2982     {
2983       gdk_window_raise (tree_view->priv->drag_column->window);
2984       gdk_window_show (tree_view->priv->drag_column->window);
2985     }
2986   else
2987     gdk_window_hide (tree_view->priv->drag_column->window);
2988
2989   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2990
2991   if (rtl)
2992     {
2993       if (tree_view->priv->cur_reorder &&
2994           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2995         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2996                                          tree_view->priv->cur_reorder->right_column);
2997     }
2998   else
2999     {
3000       if (tree_view->priv->cur_reorder &&
3001           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3002         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3003                                          tree_view->priv->cur_reorder->left_column);
3004     }
3005   tree_view->priv->drag_column = NULL;
3006   gdk_window_hide (tree_view->priv->drag_window);
3007
3008   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3009     g_slice_free (GtkTreeViewColumnReorder, l->data);
3010   g_list_free (tree_view->priv->column_drag_info);
3011   tree_view->priv->column_drag_info = NULL;
3012   tree_view->priv->cur_reorder = NULL;
3013
3014   if (tree_view->priv->drag_highlight_window)
3015     gdk_window_hide (tree_view->priv->drag_highlight_window);
3016
3017   /* Reset our flags */
3018   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3019   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3020
3021   return TRUE;
3022 }
3023
3024 /* GtkWidget::button_release_event helper */
3025 static gboolean
3026 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3027                                             GdkEventButton *event)
3028 {
3029   GtkTreeView *tree_view;
3030   gpointer drag_data;
3031
3032   tree_view = GTK_TREE_VIEW (widget);
3033
3034   tree_view->priv->drag_pos = -1;
3035
3036   /* unblock attached dnd signal handler */
3037   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3038   if (drag_data)
3039     g_signal_handlers_unblock_matched (widget,
3040                                        G_SIGNAL_MATCH_DATA,
3041                                        0, 0, NULL, NULL,
3042                                        drag_data);
3043
3044   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3045   gtk_grab_remove (widget);
3046   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3047                               event->time);
3048   return TRUE;
3049 }
3050
3051 static gboolean
3052 gtk_tree_view_button_release (GtkWidget      *widget,
3053                               GdkEventButton *event)
3054 {
3055   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3056
3057   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3058     return gtk_tree_view_button_release_drag_column (widget, event);
3059
3060   if (tree_view->priv->rubber_band_status)
3061     gtk_tree_view_stop_rubber_band (tree_view);
3062
3063   if (tree_view->priv->pressed_button == event->button)
3064     tree_view->priv->pressed_button = -1;
3065
3066   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3067     return gtk_tree_view_button_release_column_resize (widget, event);
3068
3069   if (tree_view->priv->button_pressed_node == NULL)
3070     return FALSE;
3071
3072   if (event->button == 1)
3073     {
3074       gtk_grab_remove (widget);
3075       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3076           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3077         {
3078           GtkTreePath *path = NULL;
3079
3080           path = _gtk_tree_view_find_path (tree_view,
3081                                            tree_view->priv->button_pressed_tree,
3082                                            tree_view->priv->button_pressed_node);
3083           /* Actually activate the node */
3084           if (tree_view->priv->button_pressed_node->children == NULL)
3085             gtk_tree_view_real_expand_row (tree_view, path,
3086                                            tree_view->priv->button_pressed_tree,
3087                                            tree_view->priv->button_pressed_node,
3088                                            FALSE, TRUE);
3089           else
3090             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3091                                              tree_view->priv->button_pressed_tree,
3092                                              tree_view->priv->button_pressed_node, TRUE);
3093           gtk_tree_path_free (path);
3094         }
3095
3096       tree_view->priv->button_pressed_tree = NULL;
3097       tree_view->priv->button_pressed_node = NULL;
3098     }
3099
3100   return TRUE;
3101 }
3102
3103 static gboolean
3104 gtk_tree_view_grab_broken (GtkWidget          *widget,
3105                            GdkEventGrabBroken *event)
3106 {
3107   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3108
3109   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3110     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3111
3112   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3113     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3114
3115   return TRUE;
3116 }
3117
3118 #if 0
3119 static gboolean
3120 gtk_tree_view_configure (GtkWidget *widget,
3121                          GdkEventConfigure *event)
3122 {
3123   GtkTreeView *tree_view;
3124
3125   tree_view = GTK_TREE_VIEW (widget);
3126   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3127
3128   return FALSE;
3129 }
3130 #endif
3131
3132 /* GtkWidget::motion_event function set.
3133  */
3134
3135 static gboolean
3136 coords_are_over_arrow (GtkTreeView *tree_view,
3137                        GtkRBTree   *tree,
3138                        GtkRBNode   *node,
3139                        /* these are in bin window coords */
3140                        gint         x,
3141                        gint         y)
3142 {
3143   GdkRectangle arrow;
3144   gint x2;
3145
3146   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3147     return FALSE;
3148
3149   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3150     return FALSE;
3151
3152   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3153
3154   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3155
3156   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3157
3158   arrow.width = x2 - arrow.x;
3159
3160   return (x >= arrow.x &&
3161           x < (arrow.x + arrow.width) &&
3162           y >= arrow.y &&
3163           y < (arrow.y + arrow.height));
3164 }
3165
3166 static gboolean
3167 auto_expand_timeout (gpointer data)
3168 {
3169   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3170   GtkTreePath *path;
3171
3172   if (tree_view->priv->prelight_node)
3173     {
3174       path = _gtk_tree_view_find_path (tree_view,
3175                                        tree_view->priv->prelight_tree,
3176                                        tree_view->priv->prelight_node);   
3177
3178       if (tree_view->priv->prelight_node->children)
3179         gtk_tree_view_collapse_row (tree_view, path);
3180       else
3181         gtk_tree_view_expand_row (tree_view, path, FALSE);
3182
3183       gtk_tree_path_free (path);
3184     }
3185
3186   tree_view->priv->auto_expand_timeout = 0;
3187
3188   return FALSE;
3189 }
3190
3191 static void
3192 remove_auto_expand_timeout (GtkTreeView *tree_view)
3193 {
3194   if (tree_view->priv->auto_expand_timeout != 0)
3195     {
3196       g_source_remove (tree_view->priv->auto_expand_timeout);
3197       tree_view->priv->auto_expand_timeout = 0;
3198     }
3199 }
3200
3201 static void
3202 do_prelight (GtkTreeView *tree_view,
3203              GtkRBTree   *tree,
3204              GtkRBNode   *node,
3205              /* these are in bin_window coords */
3206              gint         x,
3207              gint         y)
3208 {
3209   if (tree_view->priv->prelight_tree == tree &&
3210       tree_view->priv->prelight_node == node)
3211     {
3212       /*  We are still on the same node,
3213           but we might need to take care of the arrow  */
3214
3215       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3216         {
3217           gboolean over_arrow;
3218           gboolean flag_set;
3219
3220           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3221           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3222                                              GTK_TREE_VIEW_ARROW_PRELIT);
3223
3224           if (over_arrow != flag_set)
3225             {
3226               if (over_arrow)
3227                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3228                                         GTK_TREE_VIEW_ARROW_PRELIT);
3229               else
3230                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3231                                           GTK_TREE_VIEW_ARROW_PRELIT);
3232
3233               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3234             }
3235         }
3236
3237       return;
3238     }
3239
3240   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3241     {
3242       /*  Unprelight the old node and arrow  */
3243
3244       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3245                              GTK_RBNODE_IS_PRELIT);
3246
3247       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3248           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3249         {
3250           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3251           
3252           gtk_tree_view_queue_draw_arrow (tree_view,
3253                                           tree_view->priv->prelight_tree,
3254                                           tree_view->priv->prelight_node);
3255         }
3256
3257       _gtk_tree_view_queue_draw_node (tree_view,
3258                                       tree_view->priv->prelight_tree,
3259                                       tree_view->priv->prelight_node,
3260                                       NULL);
3261     }
3262
3263
3264   if (tree_view->priv->hover_expand)
3265     remove_auto_expand_timeout (tree_view);
3266
3267   /*  Set the new prelight values  */
3268   tree_view->priv->prelight_node = node;
3269   tree_view->priv->prelight_tree = tree;
3270
3271   if (!node || !tree)
3272     return;
3273
3274   /*  Prelight the new node and arrow  */
3275
3276   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3277       && coords_are_over_arrow (tree_view, tree, node, x, y))
3278     {
3279       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3280
3281       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3282     }
3283
3284   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3285
3286   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3287
3288   if (tree_view->priv->hover_expand)
3289     {
3290       tree_view->priv->auto_expand_timeout = 
3291         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3292     }
3293 }
3294
3295 static void
3296 prelight_or_select (GtkTreeView *tree_view,
3297                     GtkRBTree   *tree,
3298                     GtkRBNode   *node,
3299                     /* these are in bin_window coords */
3300                     gint         x,
3301                     gint         y)
3302 {
3303   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3304   
3305   if (tree_view->priv->hover_selection &&
3306       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3307       !(tree_view->priv->edited_column &&
3308         tree_view->priv->edited_column->editable_widget))
3309     {
3310       if (node)
3311         {
3312           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3313             {
3314               GtkTreePath *path;
3315               
3316               path = _gtk_tree_view_find_path (tree_view, tree, node);
3317               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3318               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3319                 {
3320                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3321                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3322                 }
3323               gtk_tree_path_free (path);
3324             }
3325         }
3326
3327       else if (mode == GTK_SELECTION_SINGLE)
3328         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3329     }
3330
3331     do_prelight (tree_view, tree, node, x, y);
3332 }
3333
3334 static void
3335 ensure_unprelighted (GtkTreeView *tree_view)
3336 {
3337   do_prelight (tree_view,
3338                NULL, NULL,
3339                -1000, -1000); /* coords not possibly over an arrow */
3340
3341   g_assert (tree_view->priv->prelight_node == NULL);
3342 }
3343
3344 static void
3345 update_prelight (GtkTreeView *tree_view,
3346                  gint         x,
3347                  gint         y)
3348 {
3349   int new_y;
3350   GtkRBTree *tree;
3351   GtkRBNode *node;
3352
3353   if (tree_view->priv->tree == NULL)
3354     return;
3355
3356   if (x == -10000)
3357     {
3358       ensure_unprelighted (tree_view);
3359       return;
3360     }
3361
3362   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3363   if (new_y < 0)
3364     new_y = 0;
3365
3366   _gtk_rbtree_find_offset (tree_view->priv->tree,
3367                            new_y, &tree, &node);
3368
3369   if (node)
3370     prelight_or_select (tree_view, tree, node, x, y);
3371 }
3372
3373
3374
3375
3376 /* Our motion arrow is either a box (in the case of the original spot)
3377  * or an arrow.  It is expander_size wide.
3378  */
3379 /*
3380  * 11111111111111
3381  * 01111111111110
3382  * 00111111111100
3383  * 00011111111000
3384  * 00001111110000
3385  * 00000111100000
3386  * 00000111100000
3387  * 00000111100000
3388  * ~ ~ ~ ~ ~ ~ ~
3389  * 00000111100000
3390  * 00000111100000
3391  * 00000111100000
3392  * 00001111110000
3393  * 00011111111000
3394  * 00111111111100
3395  * 01111111111110
3396  * 11111111111111
3397  */
3398
3399 static void
3400 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3401 {
3402   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3403   GtkWidget *widget = GTK_WIDGET (tree_view);
3404   cairo_surface_t *mask_image;
3405   cairo_region_t *mask_region;
3406   gint x;
3407   gint y;
3408   gint width;
3409   gint height;
3410   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3411   GdkWindowAttr attributes;
3412   guint attributes_mask;
3413   cairo_t *cr;
3414
3415   if (!reorder ||
3416       reorder->left_column == tree_view->priv->drag_column ||
3417       reorder->right_column == tree_view->priv->drag_column)
3418     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3419   else if (reorder->left_column || reorder->right_column)
3420     {
3421       GtkAllocation left_allocation, right_allocation;
3422       GdkRectangle visible_rect;
3423
3424       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3425       if (reorder->left_column)
3426         {
3427           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3428           x = left_allocation.x + left_allocation.width;
3429         }
3430       else
3431         {
3432           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3433           x = right_allocation.x;
3434         }
3435
3436       if (x < visible_rect.x)
3437         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3438       else if (x > visible_rect.x + visible_rect.width)
3439         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3440       else
3441         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3442     }
3443
3444   /* We want to draw the rectangle over the initial location. */
3445   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3446     {
3447       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3448         {
3449           GtkAllocation drag_allocation;
3450
3451           if (tree_view->priv->drag_highlight_window)
3452             {
3453               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3454                                         NULL);
3455               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3456             }
3457
3458           attributes.window_type = GDK_WINDOW_CHILD;
3459           attributes.wclass = GDK_INPUT_OUTPUT;
3460           attributes.x = tree_view->priv->drag_column_x;
3461           attributes.y = 0;
3462           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3463           width = attributes.width = drag_allocation.width;
3464           height = attributes.height = drag_allocation.height;
3465           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3466           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3467           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3468           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3469           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3470
3471           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3472           cr = cairo_create (mask_image);
3473
3474           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3475           cairo_stroke (cr);
3476           cairo_destroy (cr);
3477
3478           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3479           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3480                                            mask_region, 0, 0);
3481
3482           cairo_region_destroy (mask_region);
3483           cairo_surface_destroy (mask_image);
3484
3485           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3486         }
3487     }
3488   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3489     {
3490       GtkAllocation button_allocation;
3491
3492       width = tree_view->priv->expander_size;
3493
3494       /* Get x, y, width, height of arrow */
3495       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3496       if (reorder->left_column)
3497         {
3498           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3499           x += button_allocation.x + button_allocation.width - width/2;
3500           height = button_allocation.height;
3501         }
3502       else
3503         {
3504           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3505           x += button_allocation.x - width/2;
3506           height = button_allocation.height;
3507         }
3508       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3509       height += tree_view->priv->expander_size;
3510
3511       /* Create the new window */
3512       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3513         {
3514           if (tree_view->priv->drag_highlight_window)
3515             {
3516               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3517                                         NULL);
3518               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3519             }
3520
3521           attributes.window_type = GDK_WINDOW_TEMP;
3522           attributes.wclass = GDK_INPUT_OUTPUT;
3523           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3524           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3525           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3526           attributes.x = x;
3527           attributes.y = y;
3528           attributes.width = width;
3529           attributes.height = height;
3530           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3531                                                                    &attributes, attributes_mask);
3532           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3533
3534           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3535
3536           cr = cairo_create (mask_image);
3537           cairo_move_to (cr, 0, 0);
3538           cairo_line_to (cr, width, 0);
3539           cairo_line_to (cr, width / 2., width / 2);
3540           cairo_move_to (cr, 0, height);
3541           cairo_line_to (cr, width, height);
3542           cairo_line_to (cr, width / 2., height - width / 2.);
3543           cairo_fill (cr);
3544           cairo_destroy (cr);
3545
3546           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3547           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3548                                            mask_region, 0, 0);
3549
3550           cairo_region_destroy (mask_region);
3551           cairo_surface_destroy (mask_image);
3552         }
3553
3554       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3555       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3556     }
3557   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3558            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3559     {
3560       GtkAllocation allocation;
3561
3562       width = tree_view->priv->expander_size;
3563
3564       /* Get x, y, width, height of arrow */
3565       width = width/2; /* remember, the arrow only takes half the available width */
3566       gdk_window_get_origin (gtk_widget_get_window (widget),
3567                              &x, &y);
3568       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3569         {
3570           gtk_widget_get_allocation (widget, &allocation);
3571           x += allocation.width - width;
3572         }
3573
3574       if (reorder->left_column)
3575         {
3576           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3577           height = allocation.height;
3578         }
3579       else
3580         {
3581           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3582           height = allocation.height;
3583         }
3584
3585       y -= tree_view->priv->expander_size;
3586       height += 2*tree_view->priv->expander_size;
3587
3588       /* Create the new window */
3589       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3590           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3591         {
3592           if (tree_view->priv->drag_highlight_window)
3593             {
3594               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3595                                         NULL);
3596               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3597             }
3598
3599           attributes.window_type = GDK_WINDOW_TEMP;
3600           attributes.wclass = GDK_INPUT_OUTPUT;
3601           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3602           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3603           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3604           attributes.x = x;
3605           attributes.y = y;
3606           attributes.width = width;
3607           attributes.height = height;
3608           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3609           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3610
3611           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3612
3613           cr = cairo_create (mask_image);
3614           /* mirror if we're on the left */
3615           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3616             {
3617               cairo_translate (cr, width, 0);
3618               cairo_scale (cr, -1, 1);
3619             }
3620           cairo_move_to (cr, 0, 0);
3621           cairo_line_to (cr, width, width);
3622           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3623           cairo_move_to (cr, 0, height);
3624           cairo_line_to (cr, width, height - width);
3625           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3626           cairo_fill (cr);
3627           cairo_destroy (cr);
3628
3629           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3630           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3631                                            mask_region, 0, 0);
3632
3633           cairo_region_destroy (mask_region);
3634           cairo_surface_destroy (mask_image);
3635         }
3636
3637       tree_view->priv->drag_column_window_state = arrow_type;
3638       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3639    }
3640   else
3641     {
3642       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3643       gdk_window_hide (tree_view->priv->drag_highlight_window);
3644       return;
3645     }
3646
3647   gdk_window_show (tree_view->priv->drag_highlight_window);
3648   gdk_window_raise (tree_view->priv->drag_highlight_window);
3649 }
3650
3651 static gboolean
3652 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3653                                     GdkEventMotion *event)
3654 {
3655   gint x;
3656   gint new_width;
3657   GtkTreeViewColumn *column;
3658   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3659
3660   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3661
3662   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3663     gtk_widget_get_pointer (widget, &x, NULL);
3664   else
3665     x = event->x;
3666
3667   if (tree_view->priv->hadjustment)
3668     x += tree_view->priv->hadjustment->value;
3669
3670   new_width = gtk_tree_view_new_column_width (tree_view,
3671                                               tree_view->priv->drag_pos, &x);
3672   if (x != tree_view->priv->x_drag &&
3673       (new_width != column->fixed_width))
3674     {
3675       column->use_resized_width = TRUE;
3676       column->resized_width = new_width;
3677       if (column->expand)
3678         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3679       gtk_widget_queue_resize (widget);
3680     }
3681
3682   return FALSE;
3683 }
3684
3685
3686 static void
3687 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3688 {
3689   GtkTreeViewColumnReorder *reorder = NULL;
3690   GList *list;
3691   gint mouse_x;
3692
3693   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3694   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3695     {
3696       reorder = (GtkTreeViewColumnReorder *) list->data;
3697       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3698         break;
3699       reorder = NULL;
3700     }
3701
3702   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3703       return;*/
3704
3705   tree_view->priv->cur_reorder = reorder;
3706   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3707 }
3708
3709 static void
3710 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3711 {
3712   GdkRectangle visible_rect;
3713   gint y;
3714   gint offset;
3715
3716   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3717   y += tree_view->priv->dy;
3718
3719   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3720
3721   /* see if we are near the edge. */
3722   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3723   if (offset > 0)
3724     {
3725       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3726       if (offset < 0)
3727         return;
3728     }
3729
3730   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3731                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3732 }
3733
3734 static gboolean
3735 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3736 {
3737   GdkRectangle visible_rect;
3738   gint x;
3739   gint offset;
3740
3741   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3742
3743   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3744
3745   /* See if we are near the edge. */
3746   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3747   if (offset > 0)
3748     {
3749       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3750       if (offset < 0)
3751         return TRUE;
3752     }
3753   offset = offset/3;
3754
3755   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3756                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3757
3758   return TRUE;
3759
3760 }
3761
3762 static gboolean
3763 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3764                                   GdkEventMotion *event)
3765 {
3766   GtkAllocation allocation, button_allocation;
3767   GtkTreeView *tree_view = (GtkTreeView *) widget;
3768   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3769   gint x, y;
3770
3771   /* Sanity Check */
3772   if ((column == NULL) ||
3773       (event->window != tree_view->priv->drag_window))
3774     return FALSE;
3775
3776   /* Handle moving the header */
3777   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3778   gtk_widget_get_allocation (widget, &allocation);
3779   gtk_widget_get_allocation (column->button, &button_allocation);
3780   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3781              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3782   gdk_window_move (tree_view->priv->drag_window, x, y);
3783   
3784   /* autoscroll, if needed */
3785   gtk_tree_view_horizontal_autoscroll (tree_view);
3786   /* Update the current reorder position and arrow; */
3787   gtk_tree_view_update_current_reorder (tree_view);
3788
3789   return TRUE;
3790 }
3791
3792 static void
3793 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3794 {
3795   remove_scroll_timeout (tree_view);
3796   gtk_grab_remove (GTK_WIDGET (tree_view));
3797
3798   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3799     {
3800       GtkTreePath *tmp_path;
3801
3802       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3803
3804       /* The anchor path should be set to the start path */
3805       tmp_path = _gtk_tree_view_find_path (tree_view,
3806                                            tree_view->priv->rubber_band_start_tree,
3807                                            tree_view->priv->rubber_band_start_node);
3808
3809       if (tree_view->priv->anchor)
3810         gtk_tree_row_reference_free (tree_view->priv->anchor);
3811
3812       tree_view->priv->anchor =
3813         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3814                                           tree_view->priv->model,
3815                                           tmp_path);
3816
3817       gtk_tree_path_free (tmp_path);
3818
3819       /* ... and the cursor to the end path */
3820       tmp_path = _gtk_tree_view_find_path (tree_view,
3821                                            tree_view->priv->rubber_band_end_tree,
3822                                            tree_view->priv->rubber_band_end_node);
3823       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3824       gtk_tree_path_free (tmp_path);
3825
3826       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3827     }
3828
3829   /* Clear status variables */
3830   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3831   tree_view->priv->rubber_band_shift = 0;
3832   tree_view->priv->rubber_band_ctrl = 0;
3833
3834   tree_view->priv->rubber_band_start_node = NULL;
3835   tree_view->priv->rubber_band_start_tree = NULL;
3836   tree_view->priv->rubber_band_end_node = NULL;
3837   tree_view->priv->rubber_band_end_tree = NULL;
3838 }
3839
3840 static void
3841 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3842                                                  GtkRBTree   *start_tree,
3843                                                  GtkRBNode   *start_node,
3844                                                  GtkRBTree   *end_tree,
3845                                                  GtkRBNode   *end_node,
3846                                                  gboolean     select,
3847                                                  gboolean     skip_start,
3848                                                  gboolean     skip_end)
3849 {
3850   if (start_node == end_node)
3851     return;
3852
3853   /* We skip the first node and jump inside the loop */
3854   if (skip_start)
3855     goto skip_first;
3856
3857   do
3858     {
3859       /* Small optimization by assuming insensitive nodes are never
3860        * selected.
3861        */
3862       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3863         {
3864           GtkTreePath *path;
3865           gboolean selectable;
3866
3867           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3868           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3869           gtk_tree_path_free (path);
3870
3871           if (!selectable)
3872             goto node_not_selectable;
3873         }
3874
3875       if (select)
3876         {
3877           if (tree_view->priv->rubber_band_shift)
3878             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3879           else if (tree_view->priv->rubber_band_ctrl)
3880             {
3881               /* Toggle the selection state */
3882               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3883                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3884               else
3885                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3886             }
3887           else
3888             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3889         }
3890       else
3891         {
3892           /* Mirror the above */
3893           if (tree_view->priv->rubber_band_shift)
3894             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3895           else if (tree_view->priv->rubber_band_ctrl)
3896             {
3897               /* Toggle the selection state */
3898               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3899                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3900               else
3901                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3902             }
3903           else
3904             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3905         }
3906
3907       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3908
3909 node_not_selectable:
3910       if (start_node == end_node)
3911         break;
3912
3913 skip_first:
3914
3915       if (start_node->children)
3916         {
3917           start_tree = start_node->children;
3918           start_node = start_tree->root;
3919           while (start_node->left != start_tree->nil)
3920             start_node = start_node->left;
3921         }
3922       else
3923         {
3924           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3925
3926           if (!start_tree)
3927             /* Ran out of tree */
3928             break;
3929         }
3930
3931       if (skip_end && start_node == end_node)
3932         break;
3933     }
3934   while (TRUE);
3935 }
3936
3937 static void
3938 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3939 {
3940   GtkRBTree *start_tree, *end_tree;
3941   GtkRBNode *start_node, *end_node;
3942
3943   _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);
3944   _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);
3945
3946   /* Handle the start area first */
3947   if (!tree_view->priv->rubber_band_start_node)
3948     {
3949       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3950                                                        start_tree,
3951                                                        start_node,
3952                                                        end_tree,
3953                                                        end_node,
3954                                                        TRUE,
3955                                                        FALSE,
3956                                                        FALSE);
3957     }
3958   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3959            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3960     {
3961       /* New node is above the old one; selection became bigger */
3962       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3963                                                        start_tree,
3964                                                        start_node,
3965                                                        tree_view->priv->rubber_band_start_tree,
3966                                                        tree_view->priv->rubber_band_start_node,
3967                                                        TRUE,
3968                                                        FALSE,
3969                                                        TRUE);
3970     }
3971   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3972            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3973     {
3974       /* New node is below the old one; selection became smaller */
3975       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3976                                                        tree_view->priv->rubber_band_start_tree,
3977                                                        tree_view->priv->rubber_band_start_node,
3978                                                        start_tree,
3979                                                        start_node,
3980                                                        FALSE,
3981                                                        FALSE,
3982                                                        TRUE);
3983     }
3984
3985   tree_view->priv->rubber_band_start_tree = start_tree;
3986   tree_view->priv->rubber_band_start_node = start_node;
3987
3988   /* Next, handle the end area */
3989   if (!tree_view->priv->rubber_band_end_node)
3990     {
3991       /* In the event this happens, start_node was also NULL; this case is
3992        * handled above.
3993        */
3994     }
3995   else if (!end_node)
3996     {
3997       /* Find the last node in the tree */
3998       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3999                                &end_tree, &end_node);
4000
4001       /* Selection reached end of the tree */
4002       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4003                                                        tree_view->priv->rubber_band_end_tree,
4004                                                        tree_view->priv->rubber_band_end_node,
4005                                                        end_tree,
4006                                                        end_node,
4007                                                        TRUE,
4008                                                        TRUE,
4009                                                        FALSE);
4010     }
4011   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4012            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4013     {
4014       /* New node is below the old one; selection became bigger */
4015       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4016                                                        tree_view->priv->rubber_band_end_tree,
4017                                                        tree_view->priv->rubber_band_end_node,
4018                                                        end_tree,
4019                                                        end_node,
4020                                                        TRUE,
4021                                                        TRUE,
4022                                                        FALSE);
4023     }
4024   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4025            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4026     {
4027       /* New node is above the old one; selection became smaller */
4028       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4029                                                        end_tree,
4030                                                        end_node,
4031                                                        tree_view->priv->rubber_band_end_tree,
4032                                                        tree_view->priv->rubber_band_end_node,
4033                                                        FALSE,
4034                                                        TRUE,
4035                                                        FALSE);
4036     }
4037
4038   tree_view->priv->rubber_band_end_tree = end_tree;
4039   tree_view->priv->rubber_band_end_node = end_node;
4040 }
4041
4042 static void
4043 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4044 {
4045   gint x, y;
4046   GdkRectangle old_area;
4047   GdkRectangle new_area;
4048   GdkRectangle common;
4049   cairo_region_t *invalid_region;
4050
4051   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4052   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4053   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4054   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4055
4056   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4057
4058   x = MAX (x, 0);
4059   y = MAX (y, 0) + tree_view->priv->dy;
4060
4061   new_area.x = MIN (tree_view->priv->press_start_x, x);
4062   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4063   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4064   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4065
4066   invalid_region = cairo_region_create_rectangle (&old_area);
4067   cairo_region_union_rectangle (invalid_region, &new_area);
4068
4069   gdk_rectangle_intersect (&old_area, &new_area, &common);
4070   if (common.width > 2 && common.height > 2)
4071     {
4072       cairo_region_t *common_region;
4073
4074       /* make sure the border is invalidated */
4075       common.x += 1;
4076       common.y += 1;
4077       common.width -= 2;
4078       common.height -= 2;
4079
4080       common_region = cairo_region_create_rectangle (&common);
4081
4082       cairo_region_subtract (invalid_region, common_region);
4083       cairo_region_destroy (common_region);
4084     }
4085
4086   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4087
4088   cairo_region_destroy (invalid_region);
4089
4090   tree_view->priv->rubber_band_x = x;
4091   tree_view->priv->rubber_band_y = y;
4092
4093   gtk_tree_view_update_rubber_band_selection (tree_view);
4094 }
4095
4096 static void
4097 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4098                                  cairo_t      *cr)
4099 {
4100   GdkRectangle rect;
4101   GtkStyle *style;
4102
4103   cairo_save (cr);
4104
4105   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4106   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4107   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4108   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4109
4110   cairo_set_line_width (cr, 1.0);
4111
4112   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4113
4114   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4115
4116   gdk_cairo_rectangle (cr, &rect);
4117   cairo_clip (cr);
4118   cairo_paint_with_alpha (cr, 0.25);
4119
4120   cairo_rectangle (cr,
4121                    rect.x + 0.5, rect.y + 0.5,
4122                    rect.width - 1, rect.height - 1);
4123   cairo_stroke (cr);
4124
4125   cairo_restore (cr);
4126 }
4127
4128 static gboolean
4129 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4130                                  GdkEventMotion *event)
4131 {
4132   GtkTreeView *tree_view;
4133   GtkRBTree *tree;
4134   GtkRBNode *node;
4135   gint new_y;
4136
4137   tree_view = (GtkTreeView *) widget;
4138
4139   if (tree_view->priv->tree == NULL)
4140     return FALSE;
4141
4142   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4143     {
4144       gtk_grab_add (GTK_WIDGET (tree_view));
4145       gtk_tree_view_update_rubber_band (tree_view);
4146
4147       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4148     }
4149   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4150     {
4151       gtk_tree_view_update_rubber_band (tree_view);
4152
4153       add_scroll_timeout (tree_view);
4154     }
4155
4156   /* only check for an initiated drag when a button is pressed */
4157   if (tree_view->priv->pressed_button >= 0
4158       && !tree_view->priv->rubber_band_status)
4159     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4160
4161   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4162   if (new_y < 0)
4163     new_y = 0;
4164
4165   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4166
4167   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4168   if ((tree_view->priv->button_pressed_node != NULL) &&
4169       (tree_view->priv->button_pressed_node != node))
4170     node = NULL;
4171
4172   tree_view->priv->event_last_x = event->x;
4173   tree_view->priv->event_last_y = event->y;
4174
4175   prelight_or_select (tree_view, tree, node, event->x, event->y);
4176
4177   return TRUE;
4178 }
4179
4180 static gboolean
4181 gtk_tree_view_motion (GtkWidget      *widget,
4182                       GdkEventMotion *event)
4183 {
4184   GtkTreeView *tree_view;
4185
4186   tree_view = (GtkTreeView *) widget;
4187
4188   /* Resizing a column */
4189   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4190     return gtk_tree_view_motion_resize_column (widget, event);
4191
4192   /* Drag column */
4193   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4194     return gtk_tree_view_motion_drag_column (widget, event);
4195
4196   /* Sanity check it */
4197   if (event->window == tree_view->priv->bin_window)
4198     return gtk_tree_view_motion_bin_window (widget, event);
4199
4200   return FALSE;
4201 }
4202
4203 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4204  * the tree is empty.
4205  */
4206 static void
4207 invalidate_empty_focus (GtkTreeView *tree_view)
4208 {
4209   GdkRectangle area;
4210
4211   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4212     return;
4213
4214   area.x = 0;
4215   area.y = 0;
4216   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4217   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4218   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4219 }
4220
4221 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4222  * is empty.
4223  */
4224 static void
4225 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4226 {
4227   GtkWidget *widget = GTK_WIDGET (tree_view);
4228   gint w, h;
4229
4230   if (!gtk_widget_has_focus (widget))
4231     return;
4232
4233   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4234   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4235
4236   if (w > 0 && h > 0)
4237     gtk_paint_focus (gtk_widget_get_style (widget),
4238                      cr,
4239                      gtk_widget_get_state (widget),
4240                      widget,
4241                      NULL,
4242                      1, 1, w, h);
4243 }
4244
4245 typedef enum {
4246   GTK_TREE_VIEW_GRID_LINE,
4247   GTK_TREE_VIEW_TREE_LINE,
4248   GTK_TREE_VIEW_FOREGROUND_LINE
4249 } GtkTreeViewLineType;
4250
4251 static void
4252 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4253                          cairo_t             *cr,
4254                          GtkTreeViewLineType  type,
4255                          int                  x1,
4256                          int                  y1,
4257                          int                  x2,
4258                          int                  y2)
4259 {
4260   cairo_save (cr);
4261
4262   switch (type)
4263     {
4264     case GTK_TREE_VIEW_TREE_LINE:
4265       cairo_set_source_rgb (cr, 0, 0, 0);
4266       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4267       if (tree_view->priv->tree_line_dashes[0])
4268         cairo_set_dash (cr, 
4269                         tree_view->priv->tree_line_dashes,
4270                         2, 0.5);
4271       break;
4272     case GTK_TREE_VIEW_GRID_LINE:
4273       cairo_set_source_rgb (cr, 0, 0, 0);
4274       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4275       if (tree_view->priv->grid_line_dashes[0])
4276         cairo_set_dash (cr, 
4277                         tree_view->priv->grid_line_dashes,
4278                         2, 0.5);
4279       break;
4280     default:
4281       g_assert_not_reached ();
4282       /* fall through */
4283     case GTK_TREE_VIEW_FOREGROUND_LINE:
4284       cairo_set_line_width (cr, 1.0);
4285       gdk_cairo_set_source_color (cr,
4286                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4287       break;
4288     }
4289
4290   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4291   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4292   cairo_stroke (cr);
4293
4294   cairo_restore (cr);
4295 }
4296                          
4297 static void
4298 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4299                                cairo_t        *cr,
4300                                gint            n_visible_columns)
4301 {
4302   GList *list = tree_view->priv->columns;
4303   gint i = 0;
4304   gint current_x = 0;
4305
4306   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4307       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4308     return;
4309
4310   /* Only draw the lines for visible rows and columns */
4311   for (list = tree_view->priv->columns; list; list = list->next, i++)
4312     {
4313       GtkTreeViewColumn *column = list->data;
4314
4315       /* We don't want a line for the last column */
4316       if (i == n_visible_columns - 1)
4317         break;
4318
4319       if (! column->visible)
4320         continue;
4321
4322       current_x += column->width;
4323
4324       gtk_tree_view_draw_line (tree_view, cr,
4325                                GTK_TREE_VIEW_GRID_LINE,
4326                                current_x - 1, 0,
4327                                current_x - 1, tree_view->priv->height);
4328     }
4329 }
4330
4331 /* Warning: Very scary function.
4332  * Modify at your own risk
4333  *
4334  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4335  * FIXME: It's not...
4336  */
4337 static gboolean
4338 gtk_tree_view_bin_draw (GtkWidget      *widget,
4339                         cairo_t        *cr)
4340 {
4341   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4342   GtkTreePath *path;
4343   GtkStyle *style;
4344   GtkRBTree *tree;
4345   GList *list;
4346   GtkRBNode *node;
4347   GtkRBNode *cursor = NULL;
4348   GtkRBTree *cursor_tree = NULL;
4349   GtkRBNode *drag_highlight = NULL;
4350   GtkRBTree *drag_highlight_tree = NULL;
4351   GtkTreeIter iter;
4352   gint new_y;
4353   gint y_offset, cell_offset;
4354   gint max_height;
4355   gint depth;
4356   GdkRectangle background_area;
4357   GdkRectangle cell_area;
4358   GdkRectangle clip;
4359   guint flags;
4360   gint highlight_x;
4361   gint expander_cell_width;
4362   gint bin_window_width;
4363   gint bin_window_height;
4364   GtkTreePath *cursor_path;
4365   GtkTreePath *drag_dest_path;
4366   GList *first_column, *last_column;
4367   gint vertical_separator;
4368   gint horizontal_separator;
4369   gint focus_line_width;
4370   gboolean allow_rules;
4371   gboolean has_special_cell;
4372   gboolean rtl;
4373   gint n_visible_columns;
4374   gint pointer_x, pointer_y;
4375   gint grid_line_width;
4376   gboolean got_pointer = FALSE;
4377   gboolean draw_vgrid_lines, draw_hgrid_lines;
4378
4379   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4380
4381   gtk_widget_style_get (widget,
4382                         "horizontal-separator", &horizontal_separator,
4383                         "vertical-separator", &vertical_separator,
4384                         "allow-rules", &allow_rules,
4385                         "focus-line-width", &focus_line_width,
4386                         NULL);
4387
4388   if (tree_view->priv->tree == NULL)
4389     {
4390       draw_empty_focus (tree_view, cr);
4391       return TRUE;
4392     }
4393
4394   style = gtk_widget_get_style (widget);
4395
4396   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4397   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4398   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4399   cairo_clip (cr);
4400   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4401     return TRUE;
4402
4403   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4404
4405   if (new_y < 0)
4406     new_y = 0;
4407   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4408
4409   if (tree_view->priv->height < bin_window_height)
4410     {
4411       gtk_paint_flat_box (style,
4412                           cr,
4413                           gtk_widget_get_state (widget),
4414                           GTK_SHADOW_NONE,
4415                           widget,
4416                           "cell_even",
4417                           0, tree_view->priv->height,
4418                           bin_window_width,
4419                           bin_window_height - tree_view->priv->height);
4420     }
4421
4422   if (node == NULL)
4423     return TRUE;
4424
4425   /* find the path for the node */
4426   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4427                                    tree,
4428                                    node);
4429   gtk_tree_model_get_iter (tree_view->priv->model,
4430                            &iter,
4431                            path);
4432   depth = gtk_tree_path_get_depth (path);
4433   gtk_tree_path_free (path);
4434   
4435   cursor_path = NULL;
4436   drag_dest_path = NULL;
4437
4438   if (tree_view->priv->cursor)
4439     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4440
4441   if (cursor_path)
4442     _gtk_tree_view_find_node (tree_view, cursor_path,
4443                               &cursor_tree, &cursor);
4444
4445   if (tree_view->priv->drag_dest_row)
4446     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4447
4448   if (drag_dest_path)
4449     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4450                               &drag_highlight_tree, &drag_highlight);
4451
4452   draw_vgrid_lines =
4453     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4454     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4455   draw_hgrid_lines =
4456     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4457     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4458
4459   if (draw_vgrid_lines || draw_hgrid_lines)
4460     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4461   
4462   n_visible_columns = 0;
4463   for (list = tree_view->priv->columns; list; list = list->next)
4464     {
4465       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4466         continue;
4467       n_visible_columns ++;
4468     }
4469
4470   /* Find the last column */
4471   for (last_column = g_list_last (tree_view->priv->columns);
4472        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4473        last_column = last_column->prev)
4474     ;
4475
4476   /* and the first */
4477   for (first_column = g_list_first (tree_view->priv->columns);
4478        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4479        first_column = first_column->next)
4480     ;
4481
4482   /* Actually process the expose event.  To do this, we want to
4483    * start at the first node of the event, and walk the tree in
4484    * order, drawing each successive node.
4485    */
4486
4487   do
4488     {
4489       gboolean parity;
4490       gboolean is_separator = FALSE;
4491       gboolean is_first = FALSE;
4492       gboolean is_last = FALSE;
4493       
4494       is_separator = row_is_separator (tree_view, &iter, NULL);
4495
4496       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4497
4498       cell_offset = 0;
4499       highlight_x = 0; /* should match x coord of first cell */
4500       expander_cell_width = 0;
4501
4502       background_area.y = y_offset + clip.y;
4503       background_area.height = max_height;
4504
4505       flags = 0;
4506
4507       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4508         flags |= GTK_CELL_RENDERER_PRELIT;
4509
4510       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4511         flags |= GTK_CELL_RENDERER_SELECTED;
4512
4513       parity = _gtk_rbtree_node_find_parity (tree, node);
4514
4515       /* we *need* to set cell data on all cells before the call
4516        * to _has_special_cell, else _has_special_cell() does not
4517        * return a correct value.
4518        */
4519       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4520            list;
4521            list = (rtl ? list->prev : list->next))
4522         {
4523           GtkTreeViewColumn *column = list->data;
4524           gtk_tree_view_column_cell_set_cell_data (column,
4525                                                    tree_view->priv->model,
4526                                                    &iter,
4527                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4528                                                    node->children?TRUE:FALSE);
4529         }
4530
4531       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4532
4533       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4534            list;
4535            list = (rtl ? list->prev : list->next))
4536         {
4537           GtkTreeViewColumn *column = list->data;
4538           const gchar *detail = NULL;
4539           gchar new_detail[128];
4540           GtkStateType state;
4541
4542           if (!column->visible)
4543             continue;
4544
4545           if (cell_offset > clip.x + clip.width ||
4546               cell_offset + column->width < clip.x)
4547             {
4548               cell_offset += column->width;
4549               continue;
4550             }
4551
4552           if (column->show_sort_indicator)
4553             flags |= GTK_CELL_RENDERER_SORTED;
4554           else
4555             flags &= ~GTK_CELL_RENDERER_SORTED;
4556
4557           if (cursor == node)
4558             flags |= GTK_CELL_RENDERER_FOCUSED;
4559           else
4560             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4561
4562           background_area.x = cell_offset;
4563           background_area.width = column->width;
4564
4565           cell_area = background_area;
4566           cell_area.y += vertical_separator / 2;
4567           cell_area.x += horizontal_separator / 2;
4568           cell_area.height -= vertical_separator;
4569           cell_area.width -= horizontal_separator;
4570
4571           if (draw_vgrid_lines)
4572             {
4573               if (list == first_column)
4574                 {
4575                   cell_area.width -= grid_line_width / 2;
4576                 }
4577               else if (list == last_column)
4578                 {
4579                   cell_area.x += grid_line_width / 2;
4580                   cell_area.width -= grid_line_width / 2;
4581                 }
4582               else
4583                 {
4584                   cell_area.x += grid_line_width / 2;
4585                   cell_area.width -= grid_line_width;
4586                 }
4587             }
4588
4589           if (draw_hgrid_lines)
4590             {
4591               cell_area.y += grid_line_width / 2;
4592               cell_area.height -= grid_line_width;
4593             }
4594
4595           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4596             {
4597               cell_offset += column->width;
4598               continue;
4599             }
4600
4601           gtk_tree_view_column_cell_set_cell_data (column,
4602                                                    tree_view->priv->model,
4603                                                    &iter,
4604                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4605                                                    node->children?TRUE:FALSE);
4606
4607           /* Select the detail for drawing the cell.  relevant
4608            * factors are parity, sortedness, and whether to
4609            * display rules.
4610            */
4611           if (allow_rules && tree_view->priv->has_rules)
4612             {
4613               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4614                   n_visible_columns >= 3)
4615                 {
4616                   if (parity)
4617                     detail = "cell_odd_ruled_sorted";
4618                   else
4619                     detail = "cell_even_ruled_sorted";
4620                 }
4621               else
4622                 {
4623                   if (parity)
4624                     detail = "cell_odd_ruled";
4625                   else
4626                     detail = "cell_even_ruled";
4627                 }
4628             }
4629           else
4630             {
4631               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4632                   n_visible_columns >= 3)
4633                 {
4634                   if (parity)
4635                     detail = "cell_odd_sorted";
4636                   else
4637                     detail = "cell_even_sorted";
4638                 }
4639               else
4640                 {
4641                   if (parity)
4642                     detail = "cell_odd";
4643                   else
4644                     detail = "cell_even";
4645                 }
4646             }
4647
4648           g_assert (detail);
4649
4650           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4651             state = GTK_STATE_INSENSITIVE;          
4652           else if (flags & GTK_CELL_RENDERER_SELECTED)
4653             state = GTK_STATE_SELECTED;
4654           else
4655             state = GTK_STATE_NORMAL;
4656
4657           /* Draw background */
4658           is_first = (rtl ? !list->next : !list->prev);
4659           is_last = (rtl ? !list->prev : !list->next);
4660
4661           /* (I don't like the snprintfs either, but couldn't find a
4662            * less messy way).
4663            */
4664           if (is_first && is_last)
4665             g_snprintf (new_detail, 127, "%s", detail);
4666           else if (is_first)
4667             g_snprintf (new_detail, 127, "%s_start", detail);
4668           else if (is_last)
4669             g_snprintf (new_detail, 127, "%s_end", detail);
4670           else
4671             g_snprintf (new_detail, 127, "%s_middle", detail);
4672
4673           gtk_paint_flat_box (style,
4674                               cr,
4675                               state,
4676                               GTK_SHADOW_NONE,
4677                               widget,
4678                               new_detail,
4679                               background_area.x,
4680                               background_area.y,
4681                               background_area.width,
4682                               background_area.height);
4683
4684           if (gtk_tree_view_is_expander_column (tree_view, column))
4685             {
4686               if (!rtl)
4687                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4688               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4689
4690               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4691                 {
4692                   if (!rtl)
4693                     cell_area.x += depth * tree_view->priv->expander_size;
4694                   cell_area.width -= depth * tree_view->priv->expander_size;
4695                 }
4696
4697               /* If we have an expander column, the highlight underline
4698                * starts with that column, so that it indicates which
4699                * level of the tree we're dropping at.
4700                */
4701               highlight_x = cell_area.x;
4702               expander_cell_width = cell_area.width;
4703
4704               if (is_separator)
4705                 gtk_paint_hline (style,
4706                                  cr,
4707                                  state,
4708                                  widget,
4709                                  NULL,
4710                                  cell_area.x,
4711                                  cell_area.x + cell_area.width,
4712                                  cell_area.y + cell_area.height / 2);
4713               else
4714                 _gtk_tree_view_column_cell_render (column,
4715                                                    cr,
4716                                                    &background_area,
4717                                                    &cell_area,
4718                                                    flags);
4719               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4720                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4721                 {
4722                   if (!got_pointer)
4723                     {
4724                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4725                                               &pointer_x, &pointer_y, NULL);
4726                       got_pointer = TRUE;
4727                     }
4728
4729                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4730                                             cr,
4731                                             tree,
4732                                             node,
4733                                             pointer_x, pointer_y);
4734                 }
4735             }
4736           else
4737             {
4738               if (is_separator)
4739                 gtk_paint_hline (style,
4740                                  cr,
4741                                  state,
4742                                  widget,
4743                                  NULL,
4744                                  cell_area.x,
4745                                  cell_area.x + cell_area.width,
4746                                  cell_area.y + cell_area.height / 2);
4747               else
4748                 _gtk_tree_view_column_cell_render (column,
4749                                                    cr,
4750                                                    &background_area,
4751                                                    &cell_area,
4752                                                    flags);
4753             }
4754
4755           if (draw_hgrid_lines)
4756             {
4757               if (background_area.y > 0)
4758                 gtk_tree_view_draw_line (tree_view, cr,
4759                                          GTK_TREE_VIEW_GRID_LINE,
4760                                          background_area.x, background_area.y,
4761                                          background_area.x + background_area.width,
4762                                          background_area.y);
4763
4764               if (y_offset + max_height >= clip.height)
4765                 gtk_tree_view_draw_line (tree_view, cr,
4766                                          GTK_TREE_VIEW_GRID_LINE,
4767                                          background_area.x, background_area.y + max_height,
4768                                          background_area.x + background_area.width,
4769                                          background_area.y + max_height);
4770             }
4771
4772           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4773               tree_view->priv->tree_lines_enabled)
4774             {
4775               gint x = background_area.x;
4776               gint mult = rtl ? -1 : 1;
4777               gint y0 = background_area.y;
4778               gint y1 = background_area.y + background_area.height/2;
4779               gint y2 = background_area.y + background_area.height;
4780
4781               if (rtl)
4782                 x += background_area.width - 1;
4783
4784               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4785                   && depth > 1)
4786                 {
4787                   gtk_tree_view_draw_line (tree_view, cr,
4788                                            GTK_TREE_VIEW_TREE_LINE,
4789                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4790                                            y1,
4791                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4792                                            y1);
4793                 }
4794               else if (depth > 1)
4795                 {
4796                   gtk_tree_view_draw_line (tree_view, cr,
4797                                            GTK_TREE_VIEW_TREE_LINE,
4798                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4799                                            y1,
4800                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4801                                            y1);
4802                 }
4803
4804               if (depth > 1)
4805                 {
4806                   gint i;
4807                   GtkRBNode *tmp_node;
4808                   GtkRBTree *tmp_tree;
4809
4810                   if (!_gtk_rbtree_next (tree, node))
4811                     gtk_tree_view_draw_line (tree_view, cr,
4812                                              GTK_TREE_VIEW_TREE_LINE,
4813                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4814                                              y0,
4815                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4816                                              y1);
4817                   else
4818                     gtk_tree_view_draw_line (tree_view, cr,
4819                                              GTK_TREE_VIEW_TREE_LINE,
4820                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4821                                              y0,
4822                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4823                                              y2);
4824
4825                   tmp_node = tree->parent_node;
4826                   tmp_tree = tree->parent_tree;
4827
4828                   for (i = depth - 2; i > 0; i--)
4829                     {
4830                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4831                         gtk_tree_view_draw_line (tree_view, cr,
4832                                                  GTK_TREE_VIEW_TREE_LINE,
4833                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4834                                                  y0,
4835                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4836                                                  y2);
4837
4838                       tmp_node = tmp_tree->parent_node;
4839                       tmp_tree = tmp_tree->parent_tree;
4840                     }
4841                 }
4842             }
4843
4844           if (node == cursor && has_special_cell &&
4845               ((column == tree_view->priv->focus_column &&
4846                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4847                 gtk_widget_has_focus (widget)) ||
4848                (column == tree_view->priv->edited_column)))
4849             {
4850               _gtk_tree_view_column_cell_draw_focus (column,
4851                                                      cr,
4852                                                      &background_area,
4853                                                      &cell_area,
4854                                                      flags);
4855             }
4856
4857           cell_offset += column->width;
4858         }
4859
4860       if (node == drag_highlight)
4861         {
4862           /* Draw indicator for the drop
4863            */
4864           gint highlight_y = -1;
4865           GtkRBTree *tree = NULL;
4866           GtkRBNode *node = NULL;
4867
4868           switch (tree_view->priv->drag_dest_pos)
4869             {
4870             case GTK_TREE_VIEW_DROP_BEFORE:
4871               highlight_y = background_area.y - 1;
4872               if (highlight_y < 0)
4873                       highlight_y = 0;
4874               break;
4875
4876             case GTK_TREE_VIEW_DROP_AFTER:
4877               highlight_y = background_area.y + background_area.height - 1;
4878               break;
4879
4880             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4881             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4882               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4883
4884               if (tree == NULL)
4885                 break;
4886
4887               gtk_paint_focus (style,
4888                                cr,
4889                                gtk_widget_get_state (widget),
4890                                widget,
4891                                (is_first
4892                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4893                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4894                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4895                                    - focus_line_width / 2,
4896                                 gdk_window_get_width (tree_view->priv->bin_window),
4897                                 ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4898                                    - focus_line_width + 1);
4899               break;
4900             }
4901
4902           if (highlight_y >= 0)
4903             {
4904               gtk_tree_view_draw_line (tree_view, cr,
4905                                        GTK_TREE_VIEW_FOREGROUND_LINE,
4906                                        rtl ? highlight_x + expander_cell_width : highlight_x,
4907                                        highlight_y,
4908                                        rtl ? 0 : bin_window_width,
4909                                        highlight_y);
4910             }
4911         }
4912
4913       /* draw the big row-spanning focus rectangle, if needed */
4914       if (!has_special_cell && node == cursor &&
4915           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4916           gtk_widget_has_focus (widget))
4917         {
4918           gint tmp_y, tmp_height;
4919           GtkStateType focus_rect_state;
4920
4921           focus_rect_state =
4922             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4923             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4924              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4925               GTK_STATE_NORMAL));
4926
4927           if (draw_hgrid_lines)
4928             {
4929               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4930               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4931             }
4932           else
4933             {
4934               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4935               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4936             }
4937
4938           gtk_paint_focus (style,
4939                            cr,
4940                            focus_rect_state,
4941                            widget,
4942                            (is_first
4943                             ? (is_last ? "treeview" : "treeview-left" )
4944                             : (is_last ? "treeview-right" : "treeview-middle" )),
4945                            0, tmp_y,
4946                            gdk_window_get_width (tree_view->priv->bin_window),
4947                            tmp_height);
4948         }
4949
4950       y_offset += max_height;
4951       if (node->children)
4952         {
4953           GtkTreeIter parent = iter;
4954           gboolean has_child;
4955
4956           tree = node->children;
4957           node = tree->root;
4958
4959           g_assert (node != tree->nil);
4960
4961           while (node->left != tree->nil)
4962             node = node->left;
4963           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4964                                                     &iter,
4965                                                     &parent);
4966           depth++;
4967
4968           /* Sanity Check! */
4969           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4970         }
4971       else
4972         {
4973           gboolean done = FALSE;
4974
4975           do
4976             {
4977               node = _gtk_rbtree_next (tree, node);
4978               if (node != NULL)
4979                 {
4980                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4981                   done = TRUE;
4982
4983                   /* Sanity Check! */
4984                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4985                 }
4986               else
4987                 {
4988                   GtkTreeIter parent_iter = iter;
4989                   gboolean has_parent;
4990
4991                   node = tree->parent_node;
4992                   tree = tree->parent_tree;
4993                   if (tree == NULL)
4994                     /* we should go to done to free some memory */
4995                     goto done;
4996                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4997                                                            &iter,
4998                                                            &parent_iter);
4999                   depth--;
5000
5001                   /* Sanity check */
5002                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5003                 }
5004             }
5005           while (!done);
5006         }
5007     }
5008   while (y_offset < clip.height);
5009
5010 done:
5011   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5012
5013   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5014     gtk_tree_view_paint_rubber_band (tree_view, cr);
5015
5016   if (cursor_path)
5017     gtk_tree_path_free (cursor_path);
5018
5019   if (drag_dest_path)
5020     gtk_tree_path_free (drag_dest_path);
5021
5022   return FALSE;
5023 }
5024
5025 static gboolean
5026 gtk_tree_view_draw (GtkWidget *widget,
5027                     cairo_t   *cr)
5028 {
5029   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5030
5031   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5032     {
5033       GList *tmp_list;
5034
5035       cairo_save (cr);
5036
5037       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5038
5039       gtk_tree_view_bin_draw (widget, cr);
5040
5041       cairo_restore (cr);
5042
5043       /* We can't just chain up to Container::draw as it will try to send the
5044        * event to the headers, so we handle propagating it to our children
5045        * (eg. widgets being edited) ourselves.
5046        */
5047       tmp_list = tree_view->priv->children;
5048       while (tmp_list)
5049         {
5050           GtkTreeViewChild *child = tmp_list->data;
5051           tmp_list = tmp_list->next;
5052
5053           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5054         }
5055     }
5056
5057   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5058     {
5059       GList *list;
5060       
5061       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5062         {
5063           GtkTreeViewColumn *column = list->data;
5064
5065           if (column == tree_view->priv->drag_column)
5066             continue;
5067
5068           if (column->visible)
5069             gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5070                                           column->button,
5071                                           cr);
5072         }
5073     }
5074   
5075   if (tree_view->priv->drag_window &&
5076       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5077     {
5078       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5079                                     tree_view->priv->drag_column->button,
5080                                     cr);
5081     }
5082
5083   return TRUE;
5084 }
5085
5086 enum
5087 {
5088   DROP_HOME,
5089   DROP_RIGHT,
5090   DROP_LEFT,
5091   DROP_END
5092 };
5093
5094 /* returns 0x1 when no column has been found -- yes it's hackish */
5095 static GtkTreeViewColumn *
5096 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5097                                GtkTreeViewColumn *column,
5098                                gint               drop_position)
5099 {
5100   GtkTreeViewColumn *left_column = NULL;
5101   GtkTreeViewColumn *cur_column = NULL;
5102   GList *tmp_list;
5103
5104   if (!column->reorderable)
5105     return (GtkTreeViewColumn *)0x1;
5106
5107   switch (drop_position)
5108     {
5109       case DROP_HOME:
5110         /* find first column where we can drop */
5111         tmp_list = tree_view->priv->columns;
5112         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5113           return (GtkTreeViewColumn *)0x1;
5114
5115         while (tmp_list)
5116           {
5117             g_assert (tmp_list);
5118
5119             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5120             tmp_list = tmp_list->next;
5121
5122             if (left_column && left_column->visible == FALSE)
5123               continue;
5124
5125             if (!tree_view->priv->column_drop_func)
5126               return left_column;
5127
5128             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5129               {
5130                 left_column = cur_column;
5131                 continue;
5132               }
5133
5134             return left_column;
5135           }
5136
5137         if (!tree_view->priv->column_drop_func)
5138           return left_column;
5139
5140         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5141           return left_column;
5142         else
5143           return (GtkTreeViewColumn *)0x1;
5144         break;
5145
5146       case DROP_RIGHT:
5147         /* find first column after column where we can drop */
5148         tmp_list = tree_view->priv->columns;
5149
5150         for (; tmp_list; tmp_list = tmp_list->next)
5151           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5152             break;
5153
5154         if (!tmp_list || !tmp_list->next)
5155           return (GtkTreeViewColumn *)0x1;
5156
5157         tmp_list = tmp_list->next;
5158         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5159         tmp_list = tmp_list->next;
5160
5161         while (tmp_list)
5162           {
5163             g_assert (tmp_list);
5164
5165             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5166             tmp_list = tmp_list->next;
5167
5168             if (left_column && left_column->visible == FALSE)
5169               {
5170                 left_column = cur_column;
5171                 if (tmp_list)
5172                   tmp_list = tmp_list->next;
5173                 continue;
5174               }
5175
5176             if (!tree_view->priv->column_drop_func)
5177               return left_column;
5178
5179             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5180               {
5181                 left_column = cur_column;
5182                 continue;
5183               }
5184
5185             return left_column;
5186           }
5187
5188         if (!tree_view->priv->column_drop_func)
5189           return left_column;
5190
5191         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5192           return left_column;
5193         else
5194           return (GtkTreeViewColumn *)0x1;
5195         break;
5196
5197       case DROP_LEFT:
5198         /* find first column before column where we can drop */
5199         tmp_list = tree_view->priv->columns;
5200
5201         for (; tmp_list; tmp_list = tmp_list->next)
5202           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5203             break;
5204
5205         if (!tmp_list || !tmp_list->prev)
5206           return (GtkTreeViewColumn *)0x1;
5207
5208         tmp_list = tmp_list->prev;
5209         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5210         tmp_list = tmp_list->prev;
5211
5212         while (tmp_list)
5213           {
5214             g_assert (tmp_list);
5215
5216             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5217
5218             if (left_column && !left_column->visible)
5219               {
5220                 /*if (!tmp_list->prev)
5221                   return (GtkTreeViewColumn *)0x1;
5222                   */
5223 /*
5224                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5225                 tmp_list = tmp_list->prev->prev;
5226                 continue;*/
5227
5228                 cur_column = left_column;
5229                 if (tmp_list)
5230                   tmp_list = tmp_list->prev;
5231                 continue;
5232               }
5233
5234             if (!tree_view->priv->column_drop_func)
5235               return left_column;
5236
5237             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5238               return left_column;
5239
5240             cur_column = left_column;
5241             tmp_list = tmp_list->prev;
5242           }
5243
5244         if (!tree_view->priv->column_drop_func)
5245           return NULL;
5246
5247         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5248           return NULL;
5249         else
5250           return (GtkTreeViewColumn *)0x1;
5251         break;
5252
5253       case DROP_END:
5254         /* same as DROP_HOME case, but doing it backwards */
5255         tmp_list = g_list_last (tree_view->priv->columns);
5256         cur_column = NULL;
5257
5258         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5259           return (GtkTreeViewColumn *)0x1;
5260
5261         while (tmp_list)
5262           {
5263             g_assert (tmp_list);
5264
5265             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5266
5267             if (left_column && !left_column->visible)
5268               {
5269                 cur_column = left_column;
5270                 tmp_list = tmp_list->prev;
5271               }
5272
5273             if (!tree_view->priv->column_drop_func)
5274               return left_column;
5275
5276             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5277               return left_column;
5278
5279             cur_column = left_column;
5280             tmp_list = tmp_list->prev;
5281           }
5282
5283         if (!tree_view->priv->column_drop_func)
5284           return NULL;
5285
5286         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5287           return NULL;
5288         else
5289           return (GtkTreeViewColumn *)0x1;
5290         break;
5291     }
5292
5293   return (GtkTreeViewColumn *)0x1;
5294 }
5295
5296 static gboolean
5297 gtk_tree_view_key_press (GtkWidget   *widget,
5298                          GdkEventKey *event)
5299 {
5300   GtkTreeView *tree_view = (GtkTreeView *) widget;
5301
5302   if (tree_view->priv->rubber_band_status)
5303     {
5304       if (event->keyval == GDK_KEY_Escape)
5305         gtk_tree_view_stop_rubber_band (tree_view);
5306
5307       return TRUE;
5308     }
5309
5310   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5311     {
5312       if (event->keyval == GDK_KEY_Escape)
5313         {
5314           tree_view->priv->cur_reorder = NULL;
5315           gtk_tree_view_button_release_drag_column (widget, NULL);
5316         }
5317       return TRUE;
5318     }
5319
5320   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5321     {
5322       GList *focus_column;
5323       gboolean rtl;
5324
5325       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5326
5327       for (focus_column = tree_view->priv->columns;
5328            focus_column;
5329            focus_column = focus_column->next)
5330         {
5331           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5332
5333           if (gtk_widget_has_focus (column->button))
5334             break;
5335         }
5336
5337       if (focus_column &&
5338           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5339           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5340            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5341         {
5342           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5343
5344           if (!column->resizable)
5345             {
5346               gtk_widget_error_bell (widget);
5347               return TRUE;
5348             }
5349
5350           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5351               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5352             {
5353               GtkRequisition button_req;
5354               gint old_width = column->resized_width;
5355
5356               gtk_widget_get_preferred_size (column->button, &button_req, NULL);
5357
5358               column->resized_width = MAX (column->resized_width,
5359                                            column->width);
5360               column->resized_width -= 2;
5361               if (column->resized_width < 0)
5362                 column->resized_width = 0;
5363
5364               if (column->min_width == -1)
5365                 column->resized_width = MAX (button_req.width,
5366                                              column->resized_width);
5367               else
5368                 {
5369                   column->resized_width = MAX (column->min_width,
5370                                                column->resized_width);
5371                 }
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           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5385                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5386             {
5387               gint old_width = column->resized_width;
5388
5389               column->resized_width = MAX (column->resized_width,
5390                                            column->width);
5391               column->resized_width += 2;
5392
5393               if (column->max_width != -1)
5394                 column->resized_width = MIN (column->resized_width,
5395                                              column->max_width);
5396
5397               column->use_resized_width = TRUE;
5398
5399               if (column->resized_width != old_width)
5400                 gtk_widget_queue_resize (widget);
5401               else
5402                 gtk_widget_error_bell (widget);
5403             }
5404
5405           return TRUE;
5406         }
5407
5408       if (focus_column &&
5409           (event->state & GDK_MOD1_MASK) &&
5410           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5411            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5412            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5413            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5414         {
5415           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5416
5417           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5418               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5419             {
5420               GtkTreeViewColumn *col;
5421               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5422               if (col != (GtkTreeViewColumn *)0x1)
5423                 gtk_tree_view_move_column_after (tree_view, column, col);
5424               else
5425                 gtk_widget_error_bell (widget);
5426             }
5427           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5428                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5429             {
5430               GtkTreeViewColumn *col;
5431               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5432               if (col != (GtkTreeViewColumn *)0x1)
5433                 gtk_tree_view_move_column_after (tree_view, column, col);
5434               else
5435                 gtk_widget_error_bell (widget);
5436             }
5437           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5438             {
5439               GtkTreeViewColumn *col;
5440               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5441               if (col != (GtkTreeViewColumn *)0x1)
5442                 gtk_tree_view_move_column_after (tree_view, column, col);
5443               else
5444                 gtk_widget_error_bell (widget);
5445             }
5446           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5447             {
5448               GtkTreeViewColumn *col;
5449               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5450               if (col != (GtkTreeViewColumn *)0x1)
5451                 gtk_tree_view_move_column_after (tree_view, column, col);
5452               else
5453                 gtk_widget_error_bell (widget);
5454             }
5455
5456           return TRUE;
5457         }
5458     }
5459
5460   /* Chain up to the parent class.  It handles the keybindings. */
5461   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5462     return TRUE;
5463
5464   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5465     {
5466       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5467       return FALSE;
5468     }
5469
5470   /* We pass the event to the search_entry.  If its text changes, then we start
5471    * the typeahead find capabilities. */
5472   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5473       && tree_view->priv->enable_search
5474       && !tree_view->priv->search_custom_entry_set)
5475     {
5476       GdkEvent *new_event;
5477       char *old_text;
5478       const char *new_text;
5479       gboolean retval;
5480       GdkScreen *screen;
5481       gboolean text_modified;
5482       gulong popup_menu_id;
5483
5484       gtk_tree_view_ensure_interactive_directory (tree_view);
5485
5486       /* Make a copy of the current text */
5487       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5488       new_event = gdk_event_copy ((GdkEvent *) event);
5489       g_object_unref (((GdkEventKey *) new_event)->window);
5490       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5491       gtk_widget_realize (tree_view->priv->search_window);
5492
5493       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5494                                         "popup-menu", G_CALLBACK (gtk_true),
5495                                         NULL);
5496
5497       /* Move the entry off screen */
5498       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5499       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5500                        gdk_screen_get_width (screen) + 1,
5501                        gdk_screen_get_height (screen) + 1);
5502       gtk_widget_show (tree_view->priv->search_window);
5503
5504       /* Send the event to the window.  If the preedit_changed signal is emitted
5505        * during this event, we will set priv->imcontext_changed  */
5506       tree_view->priv->imcontext_changed = FALSE;
5507       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5508       gdk_event_free (new_event);
5509       gtk_widget_hide (tree_view->priv->search_window);
5510
5511       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5512                                    popup_menu_id);
5513
5514       /* We check to make sure that the entry tried to handle the text, and that
5515        * the text has changed.
5516        */
5517       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5518       text_modified = strcmp (old_text, new_text) != 0;
5519       g_free (old_text);
5520       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5521           (retval && text_modified))               /* ...or the text was modified */
5522         {
5523           if (gtk_tree_view_real_start_interactive_search (tree_view,
5524                                                            gdk_event_get_device ((GdkEvent *) event),
5525                                                            FALSE))
5526             {
5527               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5528               return TRUE;
5529             }
5530           else
5531             {
5532               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5533               return FALSE;
5534             }
5535         }
5536     }
5537
5538   return FALSE;
5539 }
5540
5541 static gboolean
5542 gtk_tree_view_key_release (GtkWidget   *widget,
5543                            GdkEventKey *event)
5544 {
5545   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5546
5547   if (tree_view->priv->rubber_band_status)
5548     return TRUE;
5549
5550   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5551 }
5552
5553 /* FIXME Is this function necessary? Can I get an enter_notify event
5554  * w/o either an expose event or a mouse motion event?
5555  */
5556 static gboolean
5557 gtk_tree_view_enter_notify (GtkWidget        *widget,
5558                             GdkEventCrossing *event)
5559 {
5560   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5561   GtkRBTree *tree;
5562   GtkRBNode *node;
5563   gint new_y;
5564
5565   /* Sanity check it */
5566   if (event->window != tree_view->priv->bin_window)
5567     return FALSE;
5568
5569   if (tree_view->priv->tree == NULL)
5570     return FALSE;
5571
5572   if (event->mode == GDK_CROSSING_GRAB ||
5573       event->mode == GDK_CROSSING_GTK_GRAB ||
5574       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5575       event->mode == GDK_CROSSING_STATE_CHANGED)
5576     return TRUE;
5577
5578   /* find the node internally */
5579   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5580   if (new_y < 0)
5581     new_y = 0;
5582   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5583
5584   tree_view->priv->event_last_x = event->x;
5585   tree_view->priv->event_last_y = event->y;
5586
5587   if ((tree_view->priv->button_pressed_node == NULL) ||
5588       (tree_view->priv->button_pressed_node == node))
5589     prelight_or_select (tree_view, tree, node, event->x, event->y);
5590
5591   return TRUE;
5592 }
5593
5594 static gboolean
5595 gtk_tree_view_leave_notify (GtkWidget        *widget,
5596                             GdkEventCrossing *event)
5597 {
5598   GtkTreeView *tree_view;
5599
5600   if (event->mode == GDK_CROSSING_GRAB)
5601     return TRUE;
5602
5603   tree_view = GTK_TREE_VIEW (widget);
5604
5605   if (tree_view->priv->prelight_node)
5606     _gtk_tree_view_queue_draw_node (tree_view,
5607                                    tree_view->priv->prelight_tree,
5608                                    tree_view->priv->prelight_node,
5609                                    NULL);
5610
5611   tree_view->priv->event_last_x = -10000;
5612   tree_view->priv->event_last_y = -10000;
5613
5614   prelight_or_select (tree_view,
5615                       NULL, NULL,
5616                       -1000, -1000); /* coords not possibly over an arrow */
5617
5618   return TRUE;
5619 }
5620
5621
5622 static gint
5623 gtk_tree_view_focus_out (GtkWidget     *widget,
5624                          GdkEventFocus *event)
5625 {
5626   GtkTreeView *tree_view;
5627
5628   tree_view = GTK_TREE_VIEW (widget);
5629
5630   gtk_widget_queue_draw (widget);
5631
5632   /* destroy interactive search dialog */
5633   if (tree_view->priv->search_window)
5634     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5635                                       gdk_event_get_device ((GdkEvent *) event));
5636
5637   return FALSE;
5638 }
5639
5640
5641 /* Incremental Reflow
5642  */
5643
5644 static void
5645 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5646                                  GtkRBTree   *tree,
5647                                  GtkRBNode   *node)
5648 {
5649   GtkAllocation allocation;
5650   gint y;
5651
5652   y = _gtk_rbtree_node_find_offset (tree, node)
5653     - tree_view->priv->vadjustment->value
5654     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5655
5656   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5657   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5658                               0, y,
5659                               allocation.width,
5660                               GTK_RBNODE_GET_HEIGHT (node));
5661 }
5662
5663 static gboolean
5664 node_is_visible (GtkTreeView *tree_view,
5665                  GtkRBTree   *tree,
5666                  GtkRBNode   *node)
5667 {
5668   int y;
5669   int height;
5670
5671   y = _gtk_rbtree_node_find_offset (tree, node);
5672   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5673
5674   if (y >= tree_view->priv->vadjustment->value &&
5675       y + height <= (tree_view->priv->vadjustment->value
5676                      + tree_view->priv->vadjustment->page_size))
5677     return TRUE;
5678
5679   return FALSE;
5680 }
5681
5682 /* Returns TRUE if it updated the size
5683  */
5684 static gboolean
5685 validate_row (GtkTreeView *tree_view,
5686               GtkRBTree   *tree,
5687               GtkRBNode   *node,
5688               GtkTreeIter *iter,
5689               GtkTreePath *path)
5690 {
5691   GtkTreeViewColumn *column;
5692   GList *list, *first_column, *last_column;
5693   gint height = 0;
5694   gint horizontal_separator;
5695   gint vertical_separator;
5696   gint focus_line_width;
5697   gint depth = gtk_tree_path_get_depth (path);
5698   gboolean retval = FALSE;
5699   gboolean is_separator = FALSE;
5700   gboolean draw_vgrid_lines, draw_hgrid_lines;
5701   gint focus_pad;
5702   gint grid_line_width;
5703   gboolean wide_separators;
5704   gint separator_height;
5705
5706   /* double check the row needs validating */
5707   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5708       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5709     return FALSE;
5710
5711   is_separator = row_is_separator (tree_view, iter, NULL);
5712
5713   gtk_widget_style_get (GTK_WIDGET (tree_view),
5714                         "focus-padding", &focus_pad,
5715                         "focus-line-width", &focus_line_width,
5716                         "horizontal-separator", &horizontal_separator,
5717                         "vertical-separator", &vertical_separator,
5718                         "grid-line-width", &grid_line_width,
5719                         "wide-separators",  &wide_separators,
5720                         "separator-height", &separator_height,
5721                         NULL);
5722   
5723   draw_vgrid_lines =
5724     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5725     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5726   draw_hgrid_lines =
5727     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5728     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5729
5730   for (last_column = g_list_last (tree_view->priv->columns);
5731        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5732        last_column = last_column->prev)
5733     ;
5734
5735   for (first_column = g_list_first (tree_view->priv->columns);
5736        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5737        first_column = first_column->next)
5738     ;
5739
5740   for (list = tree_view->priv->columns; list; list = list->next)
5741     {
5742       gint tmp_width;
5743       gint tmp_height;
5744
5745       column = list->data;
5746
5747       if (! column->visible)
5748         continue;
5749
5750       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5751         continue;
5752
5753       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5754                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5755                                                node->children?TRUE:FALSE);
5756       gtk_tree_view_column_cell_get_size (column,
5757                                           NULL, NULL, NULL,
5758                                           &tmp_width, &tmp_height);
5759
5760       if (!is_separator)
5761         {
5762           tmp_height += vertical_separator;
5763           height = MAX (height, tmp_height);
5764           height = MAX (height, tree_view->priv->expander_size);
5765         }
5766       else
5767         {
5768           if (wide_separators)
5769             height = separator_height + 2 * focus_pad;
5770           else
5771             height = 2 + 2 * focus_pad;
5772         }
5773
5774       if (gtk_tree_view_is_expander_column (tree_view, column))
5775         {
5776           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5777
5778           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5779             tmp_width += depth * tree_view->priv->expander_size;
5780         }
5781       else
5782         tmp_width = tmp_width + horizontal_separator;
5783
5784       if (draw_vgrid_lines)
5785         {
5786           if (list->data == first_column || list->data == last_column)
5787             tmp_width += grid_line_width / 2.0;
5788           else
5789             tmp_width += grid_line_width;
5790         }
5791
5792       if (tmp_width > column->requested_width)
5793         {
5794           retval = TRUE;
5795           column->requested_width = tmp_width;
5796         }
5797     }
5798
5799   if (draw_hgrid_lines)
5800     height += grid_line_width;
5801
5802   if (height != GTK_RBNODE_GET_HEIGHT (node))
5803     {
5804       retval = TRUE;
5805       _gtk_rbtree_node_set_height (tree, node, height);
5806     }
5807   _gtk_rbtree_node_mark_valid (tree, node);
5808   tree_view->priv->post_validation_flag = TRUE;
5809
5810   return retval;
5811 }
5812
5813
5814 static void
5815 validate_visible_area (GtkTreeView *tree_view)
5816 {
5817   GtkAllocation allocation;
5818   GtkTreePath *path = NULL;
5819   GtkTreePath *above_path = NULL;
5820   GtkTreeIter iter;
5821   GtkRBTree *tree = NULL;
5822   GtkRBNode *node = NULL;
5823   gboolean need_redraw = FALSE;
5824   gboolean size_changed = FALSE;
5825   gint total_height;
5826   gint area_above = 0;
5827   gint area_below = 0;
5828
5829   if (tree_view->priv->tree == NULL)
5830     return;
5831
5832   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5833       tree_view->priv->scroll_to_path == NULL)
5834     return;
5835
5836   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5837   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5838
5839   if (total_height == 0)
5840     return;
5841
5842   /* First, we check to see if we need to scroll anywhere
5843    */
5844   if (tree_view->priv->scroll_to_path)
5845     {
5846       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5847       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5848         {
5849           /* we are going to scroll, and will update dy */
5850           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5851           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5852               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5853             {
5854               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5855               if (validate_row (tree_view, tree, node, &iter, path))
5856                 size_changed = TRUE;
5857             }
5858
5859           if (tree_view->priv->scroll_to_use_align)
5860             {
5861               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5862               area_above = (total_height - height) *
5863                 tree_view->priv->scroll_to_row_align;
5864               area_below = total_height - area_above - height;
5865               area_above = MAX (area_above, 0);
5866               area_below = MAX (area_below, 0);
5867             }
5868           else
5869             {
5870               /* two cases:
5871                * 1) row not visible
5872                * 2) row visible
5873                */
5874               gint dy;
5875               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5876
5877               dy = _gtk_rbtree_node_find_offset (tree, node);
5878
5879               if (dy >= tree_view->priv->vadjustment->value &&
5880                   dy + height <= (tree_view->priv->vadjustment->value
5881                                   + tree_view->priv->vadjustment->page_size))
5882                 {
5883                   /* row visible: keep the row at the same position */
5884                   area_above = dy - tree_view->priv->vadjustment->value;
5885                   area_below = (tree_view->priv->vadjustment->value +
5886                                 tree_view->priv->vadjustment->page_size)
5887                                - dy - height;
5888                 }
5889               else
5890                 {
5891                   /* row not visible */
5892                   if (dy >= 0
5893                       && dy + height <= tree_view->priv->vadjustment->page_size)
5894                     {
5895                       /* row at the beginning -- fixed */
5896                       area_above = dy;
5897                       area_below = tree_view->priv->vadjustment->page_size
5898                                    - area_above - height;
5899                     }
5900                   else if (dy >= (tree_view->priv->vadjustment->upper -
5901                                   tree_view->priv->vadjustment->page_size))
5902                     {
5903                       /* row at the end -- fixed */
5904                       area_above = dy - (tree_view->priv->vadjustment->upper -
5905                                    tree_view->priv->vadjustment->page_size);
5906                       area_below = tree_view->priv->vadjustment->page_size -
5907                                    area_above - height;
5908
5909                       if (area_below < 0)
5910                         {
5911                           area_above = tree_view->priv->vadjustment->page_size - height;
5912                           area_below = 0;
5913                         }
5914                     }
5915                   else
5916                     {
5917                       /* row somewhere in the middle, bring it to the top
5918                        * of the view
5919                        */
5920                       area_above = 0;
5921                       area_below = total_height - height;
5922                     }
5923                 }
5924             }
5925         }
5926       else
5927         /* the scroll to isn't valid; ignore it.
5928          */
5929         {
5930           if (tree_view->priv->scroll_to_path && !path)
5931             {
5932               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5933               tree_view->priv->scroll_to_path = NULL;
5934             }
5935           if (path)
5936             gtk_tree_path_free (path);
5937           path = NULL;
5938         }      
5939     }
5940
5941   /* We didn't have a scroll_to set, so we just handle things normally
5942    */
5943   if (path == NULL)
5944     {
5945       gint offset;
5946
5947       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5948                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5949                                         &tree, &node);
5950       if (node == NULL)
5951         {
5952           /* In this case, nothing has been validated */
5953           path = gtk_tree_path_new_first ();
5954           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5955         }
5956       else
5957         {
5958           path = _gtk_tree_view_find_path (tree_view, tree, node);
5959           total_height += offset;
5960         }
5961
5962       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5963
5964       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5965           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5966         {
5967           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5968           if (validate_row (tree_view, tree, node, &iter, path))
5969             size_changed = TRUE;
5970         }
5971       area_above = 0;
5972       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5973     }
5974
5975   above_path = gtk_tree_path_copy (path);
5976
5977   /* if we do not validate any row above the new top_row, we will make sure
5978    * that the row immediately above top_row has been validated. (if we do not
5979    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5980    * when invalidated that row's height will be zero. and this will mess up
5981    * scrolling).
5982    */
5983   if (area_above == 0)
5984     {
5985       GtkRBTree *tmptree;
5986       GtkRBNode *tmpnode;
5987
5988       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5989       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5990
5991       if (tmpnode)
5992         {
5993           GtkTreePath *tmppath;
5994           GtkTreeIter tmpiter;
5995
5996           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5997           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5998
5999           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6000               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6001             {
6002               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6003               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6004                 size_changed = TRUE;
6005             }
6006
6007           gtk_tree_path_free (tmppath);
6008         }
6009     }
6010
6011   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6012    * backwards is much slower then forward, as there is no iter_prev function.
6013    * We go forwards first in case we run out of tree.  Then we go backwards to
6014    * fill out the top.
6015    */
6016   while (node && area_below > 0)
6017     {
6018       if (node->children)
6019         {
6020           GtkTreeIter parent = iter;
6021           gboolean has_child;
6022
6023           tree = node->children;
6024           node = tree->root;
6025
6026           g_assert (node != tree->nil);
6027
6028           while (node->left != tree->nil)
6029             node = node->left;
6030           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6031                                                     &iter,
6032                                                     &parent);
6033           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6034           gtk_tree_path_down (path);
6035         }
6036       else
6037         {
6038           gboolean done = FALSE;
6039           do
6040             {
6041               node = _gtk_rbtree_next (tree, node);
6042               if (node != NULL)
6043                 {
6044                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6045                   done = TRUE;
6046                   gtk_tree_path_next (path);
6047
6048                   /* Sanity Check! */
6049                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6050                 }
6051               else
6052                 {
6053                   GtkTreeIter parent_iter = iter;
6054                   gboolean has_parent;
6055
6056                   node = tree->parent_node;
6057                   tree = tree->parent_tree;
6058                   if (tree == NULL)
6059                     break;
6060                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6061                                                            &iter,
6062                                                            &parent_iter);
6063                   gtk_tree_path_up (path);
6064
6065                   /* Sanity check */
6066                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6067                 }
6068             }
6069           while (!done);
6070         }
6071
6072       if (!node)
6073         break;
6074
6075       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6076           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6077         {
6078           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6079           if (validate_row (tree_view, tree, node, &iter, path))
6080               size_changed = TRUE;
6081         }
6082
6083       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6084     }
6085   gtk_tree_path_free (path);
6086
6087   /* If we ran out of tree, and have extra area_below left, we need to add it
6088    * to area_above */
6089   if (area_below > 0)
6090     area_above += area_below;
6091
6092   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6093
6094   /* We walk backwards */
6095   while (area_above > 0)
6096     {
6097       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6098
6099       /* Always find the new path in the tree.  We cannot just assume
6100        * a gtk_tree_path_prev() is enough here, as there might be children
6101        * in between this node and the previous sibling node.  If this
6102        * appears to be a performance hotspot in profiles, we can look into
6103        * intrigate logic for keeping path, node and iter in sync like
6104        * we do for forward walks.  (Which will be hard because of the lacking
6105        * iter_prev).
6106        */
6107
6108       if (node == NULL)
6109         break;
6110
6111       gtk_tree_path_free (above_path);
6112       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6113
6114       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6115
6116       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6117           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6118         {
6119           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6120           if (validate_row (tree_view, tree, node, &iter, above_path))
6121             size_changed = TRUE;
6122         }
6123       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6124     }
6125
6126   /* if we scrolled to a path, we need to set the dy here,
6127    * and sync the top row accordingly
6128    */
6129   if (tree_view->priv->scroll_to_path)
6130     {
6131       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6132       gtk_tree_view_top_row_to_dy (tree_view);
6133
6134       need_redraw = TRUE;
6135     }
6136   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6137     {
6138       /* when we are not scrolling, we should never set dy to something
6139        * else than zero. we update top_row to be in sync with dy = 0.
6140        */
6141       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6142       gtk_tree_view_dy_to_top_row (tree_view);
6143     }
6144   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6145     {
6146       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6147       gtk_tree_view_dy_to_top_row (tree_view);
6148     }
6149   else
6150     gtk_tree_view_top_row_to_dy (tree_view);
6151
6152   /* update width/height and queue a resize */
6153   if (size_changed)
6154     {
6155       GtkRequisition requisition;
6156
6157       /* We temporarily guess a size, under the assumption that it will be the
6158        * same when we get our next size_allocate.  If we don't do this, we'll be
6159        * in an inconsistent state if we call top_row_to_dy. */
6160
6161       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6162                                      &requisition, NULL);
6163       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6164       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6165       gtk_adjustment_changed (tree_view->priv->hadjustment);
6166       gtk_adjustment_changed (tree_view->priv->vadjustment);
6167       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6168     }
6169
6170   if (tree_view->priv->scroll_to_path)
6171     {
6172       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6173       tree_view->priv->scroll_to_path = NULL;
6174     }
6175
6176   if (above_path)
6177     gtk_tree_path_free (above_path);
6178
6179   if (tree_view->priv->scroll_to_column)
6180     {
6181       tree_view->priv->scroll_to_column = NULL;
6182     }
6183   if (need_redraw)
6184     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6185 }
6186
6187 static void
6188 initialize_fixed_height_mode (GtkTreeView *tree_view)
6189 {
6190   if (!tree_view->priv->tree)
6191     return;
6192
6193   if (tree_view->priv->fixed_height < 0)
6194     {
6195       GtkTreeIter iter;
6196       GtkTreePath *path;
6197
6198       GtkRBTree *tree = NULL;
6199       GtkRBNode *node = NULL;
6200
6201       tree = tree_view->priv->tree;
6202       node = tree->root;
6203
6204       path = _gtk_tree_view_find_path (tree_view, tree, node);
6205       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6206
6207       validate_row (tree_view, tree, node, &iter, path);
6208
6209       gtk_tree_path_free (path);
6210
6211       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6212     }
6213
6214    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6215                                  tree_view->priv->fixed_height, TRUE);
6216 }
6217
6218 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6219  * the left-most uninvalidated node.  We then try walking right, validating
6220  * nodes.  Once we find a valid node, we repeat the previous process of finding
6221  * the first invalid node.
6222  */
6223
6224 static gboolean
6225 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6226 {
6227   GtkRBTree *tree = NULL;
6228   GtkRBNode *node = NULL;
6229   gboolean validated_area = FALSE;
6230   gint retval = TRUE;
6231   GtkTreePath *path = NULL;
6232   GtkTreeIter iter;
6233   GTimer *timer;
6234   gint i = 0;
6235
6236   gint prev_height = -1;
6237   gboolean fixed_height = TRUE;
6238
6239   g_assert (tree_view);
6240
6241   if (tree_view->priv->tree == NULL)
6242       return FALSE;
6243
6244   if (tree_view->priv->fixed_height_mode)
6245     {
6246       if (tree_view->priv->fixed_height < 0)
6247         initialize_fixed_height_mode (tree_view);
6248
6249       return FALSE;
6250     }
6251
6252   timer = g_timer_new ();
6253   g_timer_start (timer);
6254
6255   do
6256     {
6257       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6258         {
6259           retval = FALSE;
6260           goto done;
6261         }
6262
6263       if (path != NULL)
6264         {
6265           node = _gtk_rbtree_next (tree, node);
6266           if (node != NULL)
6267             {
6268               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6269               gtk_tree_path_next (path);
6270             }
6271           else
6272             {
6273               gtk_tree_path_free (path);
6274               path = NULL;
6275             }
6276         }
6277
6278       if (path == NULL)
6279         {
6280           tree = tree_view->priv->tree;
6281           node = tree_view->priv->tree->root;
6282
6283           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6284
6285           do
6286             {
6287               if (node->left != tree->nil &&
6288                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6289                 {
6290                   node = node->left;
6291                 }
6292               else if (node->right != tree->nil &&
6293                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6294                 {
6295                   node = node->right;
6296                 }
6297               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6298                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6299                 {
6300                   break;
6301                 }
6302               else if (node->children != NULL)
6303                 {
6304                   tree = node->children;
6305                   node = tree->root;
6306                 }
6307               else
6308                 /* RBTree corruption!  All bad */
6309                 g_assert_not_reached ();
6310             }
6311           while (TRUE);
6312           path = _gtk_tree_view_find_path (tree_view, tree, node);
6313           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6314         }
6315
6316       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6317                        validated_area;
6318
6319       if (!tree_view->priv->fixed_height_check)
6320         {
6321           gint height;
6322
6323           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6324           if (prev_height < 0)
6325             prev_height = height;
6326           else if (prev_height != height)
6327             fixed_height = FALSE;
6328         }
6329
6330       i++;
6331     }
6332   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6333
6334   if (!tree_view->priv->fixed_height_check)
6335    {
6336      if (fixed_height)
6337        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6338
6339      tree_view->priv->fixed_height_check = 1;
6340    }
6341   
6342  done:
6343   if (validated_area)
6344     {
6345       GtkRequisition requisition;
6346       /* We temporarily guess a size, under the assumption that it will be the
6347        * same when we get our next size_allocate.  If we don't do this, we'll be
6348        * in an inconsistent state when we call top_row_to_dy. */
6349
6350       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6351                                      &requisition, NULL);
6352       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6353       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6354       gtk_adjustment_changed (tree_view->priv->hadjustment);
6355       gtk_adjustment_changed (tree_view->priv->vadjustment);
6356
6357       if (queue_resize)
6358         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6359     }
6360
6361   if (path) gtk_tree_path_free (path);
6362   g_timer_destroy (timer);
6363
6364   return retval;
6365 }
6366
6367 static gboolean
6368 validate_rows (GtkTreeView *tree_view)
6369 {
6370   gboolean retval;
6371   
6372   retval = do_validate_rows (tree_view, TRUE);
6373   
6374   if (! retval && tree_view->priv->validate_rows_timer)
6375     {
6376       g_source_remove (tree_view->priv->validate_rows_timer);
6377       tree_view->priv->validate_rows_timer = 0;
6378     }
6379
6380   return retval;
6381 }
6382
6383 static gboolean
6384 validate_rows_handler (GtkTreeView *tree_view)
6385 {
6386   gboolean retval;
6387
6388   retval = do_validate_rows (tree_view, TRUE);
6389   if (! retval && tree_view->priv->validate_rows_timer)
6390     {
6391       g_source_remove (tree_view->priv->validate_rows_timer);
6392       tree_view->priv->validate_rows_timer = 0;
6393     }
6394
6395   return retval;
6396 }
6397
6398 static gboolean
6399 do_presize_handler (GtkTreeView *tree_view)
6400 {
6401   if (tree_view->priv->mark_rows_col_dirty)
6402     {
6403       if (tree_view->priv->tree)
6404         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6405       tree_view->priv->mark_rows_col_dirty = FALSE;
6406     }
6407   validate_visible_area (tree_view);
6408   tree_view->priv->presize_handler_timer = 0;
6409
6410   if (tree_view->priv->fixed_height_mode)
6411     {
6412       GtkRequisition requisition;
6413
6414       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6415                                      &requisition, NULL);
6416
6417       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6418       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6419       gtk_adjustment_changed (tree_view->priv->hadjustment);
6420       gtk_adjustment_changed (tree_view->priv->vadjustment);
6421       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6422     }
6423                    
6424   return FALSE;
6425 }
6426
6427 static gboolean
6428 presize_handler_callback (gpointer data)
6429 {
6430   do_presize_handler (GTK_TREE_VIEW (data));
6431                    
6432   return FALSE;
6433 }
6434
6435 static void
6436 install_presize_handler (GtkTreeView *tree_view)
6437 {
6438   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6439     return;
6440
6441   if (! tree_view->priv->presize_handler_timer)
6442     {
6443       tree_view->priv->presize_handler_timer =
6444         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6445     }
6446   if (! tree_view->priv->validate_rows_timer)
6447     {
6448       tree_view->priv->validate_rows_timer =
6449         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6450     }
6451 }
6452
6453 static void
6454 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6455 {
6456   /* Prior to drawing, we make sure the visible area is validated. */
6457   if (tree_view->priv->presize_handler_timer)
6458     {
6459       g_source_remove (tree_view->priv->presize_handler_timer);
6460       tree_view->priv->presize_handler_timer = 0;
6461
6462       do_presize_handler (tree_view);
6463     }
6464
6465   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6466 }
6467
6468 static gboolean
6469 scroll_sync_handler (GtkTreeView *tree_view)
6470 {
6471   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6472     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6473   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6474     gtk_tree_view_top_row_to_dy (tree_view);
6475   else
6476     gtk_tree_view_dy_to_top_row (tree_view);
6477
6478   tree_view->priv->scroll_sync_timer = 0;
6479
6480   return FALSE;
6481 }
6482
6483 static void
6484 install_scroll_sync_handler (GtkTreeView *tree_view)
6485 {
6486   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6487     return;
6488
6489   if (!tree_view->priv->scroll_sync_timer)
6490     {
6491       tree_view->priv->scroll_sync_timer =
6492         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6493     }
6494 }
6495
6496 static void
6497 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6498                            GtkTreePath *path,
6499                            gint         offset)
6500 {
6501   gtk_tree_row_reference_free (tree_view->priv->top_row);
6502
6503   if (!path)
6504     {
6505       tree_view->priv->top_row = NULL;
6506       tree_view->priv->top_row_dy = 0;
6507     }
6508   else
6509     {
6510       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6511       tree_view->priv->top_row_dy = offset;
6512     }
6513 }
6514
6515 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6516  * it's set to be NULL, and top_row_dy is 0;
6517  */
6518 static void
6519 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6520 {
6521   gint offset;
6522   GtkTreePath *path;
6523   GtkRBTree *tree;
6524   GtkRBNode *node;
6525
6526   if (tree_view->priv->tree == NULL)
6527     {
6528       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6529     }
6530   else
6531     {
6532       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6533                                         tree_view->priv->dy,
6534                                         &tree, &node);
6535
6536       if (tree == NULL)
6537         {
6538           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6539         }
6540       else
6541         {
6542           path = _gtk_tree_view_find_path (tree_view, tree, node);
6543           gtk_tree_view_set_top_row (tree_view, path, offset);
6544           gtk_tree_path_free (path);
6545         }
6546     }
6547 }
6548
6549 static void
6550 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6551 {
6552   GtkTreePath *path;
6553   GtkRBTree *tree;
6554   GtkRBNode *node;
6555   int new_dy;
6556
6557   /* Avoid recursive calls */
6558   if (tree_view->priv->in_top_row_to_dy)
6559     return;
6560
6561   if (tree_view->priv->top_row)
6562     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6563   else
6564     path = NULL;
6565
6566   if (!path)
6567     tree = NULL;
6568   else
6569     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6570
6571   if (path)
6572     gtk_tree_path_free (path);
6573
6574   if (tree == NULL)
6575     {
6576       /* keep dy and set new toprow */
6577       gtk_tree_row_reference_free (tree_view->priv->top_row);
6578       tree_view->priv->top_row = NULL;
6579       tree_view->priv->top_row_dy = 0;
6580       /* DO NOT install the idle handler */
6581       gtk_tree_view_dy_to_top_row (tree_view);
6582       return;
6583     }
6584
6585   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6586       < tree_view->priv->top_row_dy)
6587     {
6588       /* new top row -- do NOT install the idle handler */
6589       gtk_tree_view_dy_to_top_row (tree_view);
6590       return;
6591     }
6592
6593   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6594   new_dy += tree_view->priv->top_row_dy;
6595
6596   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6597     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6598
6599   new_dy = MAX (0, new_dy);
6600
6601   tree_view->priv->in_top_row_to_dy = TRUE;
6602   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6603   tree_view->priv->in_top_row_to_dy = FALSE;
6604 }
6605
6606
6607 void
6608 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6609 {
6610   tree_view->priv->mark_rows_col_dirty = TRUE;
6611
6612   install_presize_handler (tree_view);
6613 }
6614
6615 /*
6616  * This function works synchronously (due to the while (validate_rows...)
6617  * loop).
6618  *
6619  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6620  * here. You now need to check that yourself.
6621  */
6622 void
6623 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6624                                 GtkTreeViewColumn *column)
6625 {
6626   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6627   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6628
6629   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6630
6631   do_presize_handler (tree_view);
6632   while (validate_rows (tree_view));
6633
6634   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6635 }
6636
6637 /* Drag-and-drop */
6638
6639 static void
6640 set_source_row (GdkDragContext *context,
6641                 GtkTreeModel   *model,
6642                 GtkTreePath    *source_row)
6643 {
6644   g_object_set_data_full (G_OBJECT (context),
6645                           I_("gtk-tree-view-source-row"),
6646                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6647                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6648 }
6649
6650 static GtkTreePath*
6651 get_source_row (GdkDragContext *context)
6652 {
6653   GtkTreeRowReference *ref =
6654     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6655
6656   if (ref)
6657     return gtk_tree_row_reference_get_path (ref);
6658   else
6659     return NULL;
6660 }
6661
6662 typedef struct
6663 {
6664   GtkTreeRowReference *dest_row;
6665   guint                path_down_mode   : 1;
6666   guint                empty_view_drop  : 1;
6667   guint                drop_append_mode : 1;
6668 }
6669 DestRow;
6670
6671 static void
6672 dest_row_free (gpointer data)
6673 {
6674   DestRow *dr = (DestRow *)data;
6675
6676   gtk_tree_row_reference_free (dr->dest_row);
6677   g_slice_free (DestRow, dr);
6678 }
6679
6680 static void
6681 set_dest_row (GdkDragContext *context,
6682               GtkTreeModel   *model,
6683               GtkTreePath    *dest_row,
6684               gboolean        path_down_mode,
6685               gboolean        empty_view_drop,
6686               gboolean        drop_append_mode)
6687 {
6688   DestRow *dr;
6689
6690   if (!dest_row)
6691     {
6692       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6693                               NULL, NULL);
6694       return;
6695     }
6696
6697   dr = g_slice_new (DestRow);
6698
6699   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6700   dr->path_down_mode = path_down_mode != FALSE;
6701   dr->empty_view_drop = empty_view_drop != FALSE;
6702   dr->drop_append_mode = drop_append_mode != FALSE;
6703
6704   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6705                           dr, (GDestroyNotify) dest_row_free);
6706 }
6707
6708 static GtkTreePath*
6709 get_dest_row (GdkDragContext *context,
6710               gboolean       *path_down_mode)
6711 {
6712   DestRow *dr =
6713     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6714
6715   if (dr)
6716     {
6717       GtkTreePath *path = NULL;
6718
6719       if (path_down_mode)
6720         *path_down_mode = dr->path_down_mode;
6721
6722       if (dr->dest_row)
6723         path = gtk_tree_row_reference_get_path (dr->dest_row);
6724       else if (dr->empty_view_drop)
6725         path = gtk_tree_path_new_from_indices (0, -1);
6726       else
6727         path = NULL;
6728
6729       if (path && dr->drop_append_mode)
6730         gtk_tree_path_next (path);
6731
6732       return path;
6733     }
6734   else
6735     return NULL;
6736 }
6737
6738 /* Get/set whether drag_motion requested the drag data and
6739  * drag_data_received should thus not actually insert the data,
6740  * since the data doesn't result from a drop.
6741  */
6742 static void
6743 set_status_pending (GdkDragContext *context,
6744                     GdkDragAction   suggested_action)
6745 {
6746   g_object_set_data (G_OBJECT (context),
6747                      I_("gtk-tree-view-status-pending"),
6748                      GINT_TO_POINTER (suggested_action));
6749 }
6750
6751 static GdkDragAction
6752 get_status_pending (GdkDragContext *context)
6753 {
6754   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6755                                              "gtk-tree-view-status-pending"));
6756 }
6757
6758 static TreeViewDragInfo*
6759 get_info (GtkTreeView *tree_view)
6760 {
6761   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6762 }
6763
6764 static void
6765 destroy_info (TreeViewDragInfo *di)
6766 {
6767   g_slice_free (TreeViewDragInfo, di);
6768 }
6769
6770 static TreeViewDragInfo*
6771 ensure_info (GtkTreeView *tree_view)
6772 {
6773   TreeViewDragInfo *di;
6774
6775   di = get_info (tree_view);
6776
6777   if (di == NULL)
6778     {
6779       di = g_slice_new0 (TreeViewDragInfo);
6780
6781       g_object_set_data_full (G_OBJECT (tree_view),
6782                               I_("gtk-tree-view-drag-info"),
6783                               di,
6784                               (GDestroyNotify) destroy_info);
6785     }
6786
6787   return di;
6788 }
6789
6790 static void
6791 remove_info (GtkTreeView *tree_view)
6792 {
6793   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6794 }
6795
6796 #if 0
6797 static gint
6798 drag_scan_timeout (gpointer data)
6799 {
6800   GtkTreeView *tree_view;
6801   gint x, y;
6802   GdkModifierType state;
6803   GtkTreePath *path = NULL;
6804   GtkTreeViewColumn *column = NULL;
6805   GdkRectangle visible_rect;
6806
6807   GDK_THREADS_ENTER ();
6808
6809   tree_view = GTK_TREE_VIEW (data);
6810
6811   gdk_window_get_pointer (tree_view->priv->bin_window,
6812                           &x, &y, &state);
6813
6814   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6815
6816   /* See if we are near the edge. */
6817   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6818       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6819       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6820       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6821     {
6822       gtk_tree_view_get_path_at_pos (tree_view,
6823                                      tree_view->priv->bin_window,
6824                                      x, y,
6825                                      &path,
6826                                      &column,
6827                                      NULL,
6828                                      NULL);
6829
6830       if (path != NULL)
6831         {
6832           gtk_tree_view_scroll_to_cell (tree_view,
6833                                         path,
6834                                         column,
6835                                         TRUE,
6836                                         0.5, 0.5);
6837
6838           gtk_tree_path_free (path);
6839         }
6840     }
6841
6842   GDK_THREADS_LEAVE ();
6843
6844   return TRUE;
6845 }
6846 #endif /* 0 */
6847
6848 static void
6849 add_scroll_timeout (GtkTreeView *tree_view)
6850 {
6851   if (tree_view->priv->scroll_timeout == 0)
6852     {
6853       tree_view->priv->scroll_timeout =
6854         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6855     }
6856 }
6857
6858 static void
6859 remove_scroll_timeout (GtkTreeView *tree_view)
6860 {
6861   if (tree_view->priv->scroll_timeout != 0)
6862     {
6863       g_source_remove (tree_view->priv->scroll_timeout);
6864       tree_view->priv->scroll_timeout = 0;
6865     }
6866 }
6867
6868 static gboolean
6869 check_model_dnd (GtkTreeModel *model,
6870                  GType         required_iface,
6871                  const gchar  *signal)
6872 {
6873   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6874     {
6875       g_warning ("You must override the default '%s' handler "
6876                  "on GtkTreeView when using models that don't support "
6877                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6878                  "is to connect to '%s' and call "
6879                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6880                  "the default handler from running. Look at the source code "
6881                  "for the default handler in gtktreeview.c to get an idea what "
6882                  "your handler should do. (gtktreeview.c is in the GTK source "
6883                  "code.) If you're using GTK from a language other than C, "
6884                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6885                  signal, g_type_name (required_iface), signal);
6886       return FALSE;
6887     }
6888   else
6889     return TRUE;
6890 }
6891
6892 static void
6893 remove_open_timeout (GtkTreeView *tree_view)
6894 {
6895   if (tree_view->priv->open_dest_timeout != 0)
6896     {
6897       g_source_remove (tree_view->priv->open_dest_timeout);
6898       tree_view->priv->open_dest_timeout = 0;
6899     }
6900 }
6901
6902
6903 static gint
6904 open_row_timeout (gpointer data)
6905 {
6906   GtkTreeView *tree_view = data;
6907   GtkTreePath *dest_path = NULL;
6908   GtkTreeViewDropPosition pos;
6909   gboolean result = FALSE;
6910
6911   gtk_tree_view_get_drag_dest_row (tree_view,
6912                                    &dest_path,
6913                                    &pos);
6914
6915   if (dest_path &&
6916       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6917        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6918     {
6919       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6920       tree_view->priv->open_dest_timeout = 0;
6921
6922       gtk_tree_path_free (dest_path);
6923     }
6924   else
6925     {
6926       if (dest_path)
6927         gtk_tree_path_free (dest_path);
6928
6929       result = TRUE;
6930     }
6931
6932   return result;
6933 }
6934
6935 static gboolean
6936 scroll_row_timeout (gpointer data)
6937 {
6938   GtkTreeView *tree_view = data;
6939
6940   gtk_tree_view_vertical_autoscroll (tree_view);
6941
6942   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6943     gtk_tree_view_update_rubber_band (tree_view);
6944
6945   return TRUE;
6946 }
6947
6948 /* Returns TRUE if event should not be propagated to parent widgets */
6949 static gboolean
6950 set_destination_row (GtkTreeView    *tree_view,
6951                      GdkDragContext *context,
6952                      /* coordinates relative to the widget */
6953                      gint            x,
6954                      gint            y,
6955                      GdkDragAction  *suggested_action,
6956                      GdkAtom        *target)
6957 {
6958   GtkTreePath *path = NULL;
6959   GtkTreeViewDropPosition pos;
6960   GtkTreeViewDropPosition old_pos;
6961   TreeViewDragInfo *di;
6962   GtkWidget *widget;
6963   GtkTreePath *old_dest_path = NULL;
6964   gboolean can_drop = FALSE;
6965
6966   *suggested_action = 0;
6967   *target = GDK_NONE;
6968
6969   widget = GTK_WIDGET (tree_view);
6970
6971   di = get_info (tree_view);
6972
6973   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6974     {
6975       /* someone unset us as a drag dest, note that if
6976        * we return FALSE drag_leave isn't called
6977        */
6978
6979       gtk_tree_view_set_drag_dest_row (tree_view,
6980                                        NULL,
6981                                        GTK_TREE_VIEW_DROP_BEFORE);
6982
6983       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6984       remove_open_timeout (GTK_TREE_VIEW (widget));
6985
6986       return FALSE; /* no longer a drop site */
6987     }
6988
6989   *target = gtk_drag_dest_find_target (widget, context,
6990                                        gtk_drag_dest_get_target_list (widget));
6991   if (*target == GDK_NONE)
6992     {
6993       return FALSE;
6994     }
6995
6996   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6997                                           x, y,
6998                                           &path,
6999                                           &pos))
7000     {
7001       gint n_children;
7002       GtkTreeModel *model;
7003
7004       remove_open_timeout (tree_view);
7005
7006       /* the row got dropped on empty space, let's setup a special case
7007        */
7008
7009       if (path)
7010         gtk_tree_path_free (path);
7011
7012       model = gtk_tree_view_get_model (tree_view);
7013
7014       n_children = gtk_tree_model_iter_n_children (model, NULL);
7015       if (n_children)
7016         {
7017           pos = GTK_TREE_VIEW_DROP_AFTER;
7018           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7019         }
7020       else
7021         {
7022           pos = GTK_TREE_VIEW_DROP_BEFORE;
7023           path = gtk_tree_path_new_from_indices (0, -1);
7024         }
7025
7026       can_drop = TRUE;
7027
7028       goto out;
7029     }
7030
7031   g_assert (path);
7032
7033   /* If we left the current row's "open" zone, unset the timeout for
7034    * opening the row
7035    */
7036   gtk_tree_view_get_drag_dest_row (tree_view,
7037                                    &old_dest_path,
7038                                    &old_pos);
7039
7040   if (old_dest_path &&
7041       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7042        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7043          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7044     remove_open_timeout (tree_view);
7045
7046   if (old_dest_path)
7047     gtk_tree_path_free (old_dest_path);
7048
7049   if (TRUE /* FIXME if the location droppable predicate */)
7050     {
7051       can_drop = TRUE;
7052     }
7053
7054 out:
7055   if (can_drop)
7056     {
7057       GtkWidget *source_widget;
7058
7059       *suggested_action = context->suggested_action;
7060       source_widget = gtk_drag_get_source_widget (context);
7061
7062       if (source_widget == widget)
7063         {
7064           /* Default to MOVE, unless the user has
7065            * pressed ctrl or shift to affect available actions
7066            */
7067           if ((context->actions & GDK_ACTION_MOVE) != 0)
7068             *suggested_action = GDK_ACTION_MOVE;
7069         }
7070
7071       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7072                                        path, pos);
7073     }
7074   else
7075     {
7076       /* can't drop here */
7077       remove_open_timeout (tree_view);
7078
7079       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7080                                        NULL,
7081                                        GTK_TREE_VIEW_DROP_BEFORE);
7082     }
7083
7084   if (path)
7085     gtk_tree_path_free (path);
7086
7087   return TRUE;
7088 }
7089
7090 static GtkTreePath*
7091 get_logical_dest_row (GtkTreeView *tree_view,
7092                       gboolean    *path_down_mode,
7093                       gboolean    *drop_append_mode)
7094 {
7095   /* adjust path to point to the row the drop goes in front of */
7096   GtkTreePath *path = NULL;
7097   GtkTreeViewDropPosition pos;
7098
7099   g_return_val_if_fail (path_down_mode != NULL, NULL);
7100   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7101
7102   *path_down_mode = FALSE;
7103   *drop_append_mode = 0;
7104
7105   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7106
7107   if (path == NULL)
7108     return NULL;
7109
7110   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7111     ; /* do nothing */
7112   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7113            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7114     *path_down_mode = TRUE;
7115   else
7116     {
7117       GtkTreeIter iter;
7118       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7119
7120       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7121
7122       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7123           !gtk_tree_model_iter_next (model, &iter))
7124         *drop_append_mode = 1;
7125       else
7126         {
7127           *drop_append_mode = 0;
7128           gtk_tree_path_next (path);
7129         }
7130     }
7131
7132   return path;
7133 }
7134
7135 static gboolean
7136 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7137                                         GdkEventMotion   *event)
7138 {
7139   GtkWidget *widget = GTK_WIDGET (tree_view);
7140   GdkDragContext *context;
7141   TreeViewDragInfo *di;
7142   GtkTreePath *path = NULL;
7143   gint button;
7144   gint cell_x, cell_y;
7145   GtkTreeModel *model;
7146   gboolean retval = FALSE;
7147
7148   di = get_info (tree_view);
7149
7150   if (di == NULL || !di->source_set)
7151     goto out;
7152
7153   if (tree_view->priv->pressed_button < 0)
7154     goto out;
7155
7156   if (!gtk_drag_check_threshold (widget,
7157                                  tree_view->priv->press_start_x,
7158                                  tree_view->priv->press_start_y,
7159                                  event->x, event->y))
7160     goto out;
7161
7162   model = gtk_tree_view_get_model (tree_view);
7163
7164   if (model == NULL)
7165     goto out;
7166
7167   button = tree_view->priv->pressed_button;
7168   tree_view->priv->pressed_button = -1;
7169
7170   gtk_tree_view_get_path_at_pos (tree_view,
7171                                  tree_view->priv->press_start_x,
7172                                  tree_view->priv->press_start_y,
7173                                  &path,
7174                                  NULL,
7175                                  &cell_x,
7176                                  &cell_y);
7177
7178   if (path == NULL)
7179     goto out;
7180
7181   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7182       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7183                                            path))
7184     goto out;
7185
7186   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7187     goto out;
7188
7189   /* Now we can begin the drag */
7190
7191   retval = TRUE;
7192
7193   context = gtk_drag_begin (widget,
7194                             gtk_drag_source_get_target_list (widget),
7195                             di->source_actions,
7196                             button,
7197                             (GdkEvent*)event);
7198
7199   set_source_row (context, model, path);
7200
7201  out:
7202   if (path)
7203     gtk_tree_path_free (path);
7204
7205   return retval;
7206 }
7207
7208
7209 static void
7210 gtk_tree_view_drag_begin (GtkWidget      *widget,
7211                           GdkDragContext *context)
7212 {
7213   GtkTreeView *tree_view;
7214   GtkTreePath *path = NULL;
7215   gint cell_x, cell_y;
7216   cairo_surface_t *row_pix;
7217   TreeViewDragInfo *di;
7218
7219   tree_view = GTK_TREE_VIEW (widget);
7220
7221   /* if the user uses a custom DND source impl, we don't set the icon here */
7222   di = get_info (tree_view);
7223
7224   if (di == NULL || !di->source_set)
7225     return;
7226
7227   gtk_tree_view_get_path_at_pos (tree_view,
7228                                  tree_view->priv->press_start_x,
7229                                  tree_view->priv->press_start_y,
7230                                  &path,
7231                                  NULL,
7232                                  &cell_x,
7233                                  &cell_y);
7234
7235   g_return_if_fail (path != NULL);
7236
7237   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7238                                                 path);
7239   cairo_surface_set_device_offset (row_pix,
7240                                    /* the + 1 is for the black border in the icon */
7241                                    - (tree_view->priv->press_start_x + 1),
7242                                    - (cell_y + 1));
7243
7244   gtk_drag_set_icon_surface (context, row_pix);
7245
7246   cairo_surface_destroy (row_pix);
7247   gtk_tree_path_free (path);
7248 }
7249
7250 static void
7251 gtk_tree_view_drag_end (GtkWidget      *widget,
7252                         GdkDragContext *context)
7253 {
7254   /* do nothing */
7255 }
7256
7257 /* Default signal implementations for the drag signals */
7258 static void
7259 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7260                              GdkDragContext   *context,
7261                              GtkSelectionData *selection_data,
7262                              guint             info,
7263                              guint             time)
7264 {
7265   GtkTreeView *tree_view;
7266   GtkTreeModel *model;
7267   TreeViewDragInfo *di;
7268   GtkTreePath *source_row;
7269
7270   tree_view = GTK_TREE_VIEW (widget);
7271
7272   model = gtk_tree_view_get_model (tree_view);
7273
7274   if (model == NULL)
7275     return;
7276
7277   di = get_info (GTK_TREE_VIEW (widget));
7278
7279   if (di == NULL)
7280     return;
7281
7282   source_row = get_source_row (context);
7283
7284   if (source_row == NULL)
7285     return;
7286
7287   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7288    * any model; for DragSource models there are some other targets
7289    * we also support.
7290    */
7291
7292   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7293       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7294                                           source_row,
7295                                           selection_data))
7296     goto done;
7297
7298   /* If drag_data_get does nothing, try providing row data. */
7299   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7300     {
7301       gtk_tree_set_row_drag_data (selection_data,
7302                                   model,
7303                                   source_row);
7304     }
7305
7306  done:
7307   gtk_tree_path_free (source_row);
7308 }
7309
7310
7311 static void
7312 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7313                                 GdkDragContext *context)
7314 {
7315   TreeViewDragInfo *di;
7316   GtkTreeModel *model;
7317   GtkTreeView *tree_view;
7318   GtkTreePath *source_row;
7319
7320   tree_view = GTK_TREE_VIEW (widget);
7321   model = gtk_tree_view_get_model (tree_view);
7322
7323   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7324     return;
7325
7326   di = get_info (tree_view);
7327
7328   if (di == NULL)
7329     return;
7330
7331   source_row = get_source_row (context);
7332
7333   if (source_row == NULL)
7334     return;
7335
7336   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7337                                          source_row);
7338
7339   gtk_tree_path_free (source_row);
7340
7341   set_source_row (context, NULL, NULL);
7342 }
7343
7344 static void
7345 gtk_tree_view_drag_leave (GtkWidget      *widget,
7346                           GdkDragContext *context,
7347                           guint             time)
7348 {
7349   /* unset any highlight row */
7350   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7351                                    NULL,
7352                                    GTK_TREE_VIEW_DROP_BEFORE);
7353
7354   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7355   remove_open_timeout (GTK_TREE_VIEW (widget));
7356 }
7357
7358
7359 static gboolean
7360 gtk_tree_view_drag_motion (GtkWidget        *widget,
7361                            GdkDragContext   *context,
7362                            /* coordinates relative to the widget */
7363                            gint              x,
7364                            gint              y,
7365                            guint             time)
7366 {
7367   gboolean empty;
7368   GtkTreePath *path = NULL;
7369   GtkTreeViewDropPosition pos;
7370   GtkTreeView *tree_view;
7371   GdkDragAction suggested_action = 0;
7372   GdkAtom target;
7373
7374   tree_view = GTK_TREE_VIEW (widget);
7375
7376   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7377     return FALSE;
7378
7379   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7380
7381   /* we only know this *after* set_desination_row */
7382   empty = tree_view->priv->empty_view_drop;
7383
7384   if (path == NULL && !empty)
7385     {
7386       /* Can't drop here. */
7387       gdk_drag_status (context, 0, time);
7388     }
7389   else
7390     {
7391       if (tree_view->priv->open_dest_timeout == 0 &&
7392           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7393            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7394         {
7395           tree_view->priv->open_dest_timeout =
7396             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7397         }
7398       else
7399         {
7400           add_scroll_timeout (tree_view);
7401         }
7402
7403       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7404         {
7405           /* Request data so we can use the source row when
7406            * determining whether to accept the drop
7407            */
7408           set_status_pending (context, suggested_action);
7409           gtk_drag_get_data (widget, context, target, time);
7410         }
7411       else
7412         {
7413           set_status_pending (context, 0);
7414           gdk_drag_status (context, suggested_action, time);
7415         }
7416     }
7417
7418   if (path)
7419     gtk_tree_path_free (path);
7420
7421   return TRUE;
7422 }
7423
7424
7425 static gboolean
7426 gtk_tree_view_drag_drop (GtkWidget        *widget,
7427                          GdkDragContext   *context,
7428                          /* coordinates relative to the widget */
7429                          gint              x,
7430                          gint              y,
7431                          guint             time)
7432 {
7433   GtkTreeView *tree_view;
7434   GtkTreePath *path;
7435   GdkDragAction suggested_action = 0;
7436   GdkAtom target = GDK_NONE;
7437   TreeViewDragInfo *di;
7438   GtkTreeModel *model;
7439   gboolean path_down_mode;
7440   gboolean drop_append_mode;
7441
7442   tree_view = GTK_TREE_VIEW (widget);
7443
7444   model = gtk_tree_view_get_model (tree_view);
7445
7446   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7447   remove_open_timeout (GTK_TREE_VIEW (widget));
7448
7449   di = get_info (tree_view);
7450
7451   if (di == NULL)
7452     return FALSE;
7453
7454   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7455     return FALSE;
7456
7457   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7458     return FALSE;
7459
7460   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7461
7462   if (target != GDK_NONE && path != NULL)
7463     {
7464       /* in case a motion had requested drag data, change things so we
7465        * treat drag data receives as a drop.
7466        */
7467       set_status_pending (context, 0);
7468       set_dest_row (context, model, path,
7469                     path_down_mode, tree_view->priv->empty_view_drop,
7470                     drop_append_mode);
7471     }
7472
7473   if (path)
7474     gtk_tree_path_free (path);
7475
7476   /* Unset this thing */
7477   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7478                                    NULL,
7479                                    GTK_TREE_VIEW_DROP_BEFORE);
7480
7481   if (target != GDK_NONE)
7482     {
7483       gtk_drag_get_data (widget, context, target, time);
7484       return TRUE;
7485     }
7486   else
7487     return FALSE;
7488 }
7489
7490 static void
7491 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7492                                   GdkDragContext   *context,
7493                                   /* coordinates relative to the widget */
7494                                   gint              x,
7495                                   gint              y,
7496                                   GtkSelectionData *selection_data,
7497                                   guint             info,
7498                                   guint             time)
7499 {
7500   GtkTreePath *path;
7501   TreeViewDragInfo *di;
7502   gboolean accepted = FALSE;
7503   GtkTreeModel *model;
7504   GtkTreeView *tree_view;
7505   GtkTreePath *dest_row;
7506   GdkDragAction suggested_action;
7507   gboolean path_down_mode;
7508   gboolean drop_append_mode;
7509
7510   tree_view = GTK_TREE_VIEW (widget);
7511
7512   model = gtk_tree_view_get_model (tree_view);
7513
7514   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7515     return;
7516
7517   di = get_info (tree_view);
7518
7519   if (di == NULL)
7520     return;
7521
7522   suggested_action = get_status_pending (context);
7523
7524   if (suggested_action)
7525     {
7526       /* We are getting this data due to a request in drag_motion,
7527        * rather than due to a request in drag_drop, so we are just
7528        * supposed to call drag_status, not actually paste in the
7529        * data.
7530        */
7531       path = get_logical_dest_row (tree_view, &path_down_mode,
7532                                    &drop_append_mode);
7533
7534       if (path == NULL)
7535         suggested_action = 0;
7536       else if (path_down_mode)
7537         gtk_tree_path_down (path);
7538
7539       if (suggested_action)
7540         {
7541           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7542                                                      path,
7543                                                      selection_data))
7544             {
7545               if (path_down_mode)
7546                 {
7547                   path_down_mode = FALSE;
7548                   gtk_tree_path_up (path);
7549
7550                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7551                                                              path,
7552                                                              selection_data))
7553                     suggested_action = 0;
7554                 }
7555               else
7556                 suggested_action = 0;
7557             }
7558         }
7559
7560       gdk_drag_status (context, suggested_action, time);
7561
7562       if (path)
7563         gtk_tree_path_free (path);
7564
7565       /* If you can't drop, remove user drop indicator until the next motion */
7566       if (suggested_action == 0)
7567         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7568                                          NULL,
7569                                          GTK_TREE_VIEW_DROP_BEFORE);
7570
7571       return;
7572     }
7573
7574   dest_row = get_dest_row (context, &path_down_mode);
7575
7576   if (dest_row == NULL)
7577     return;
7578
7579   if (selection_data->length >= 0)
7580     {
7581       if (path_down_mode)
7582         {
7583           gtk_tree_path_down (dest_row);
7584           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7585                                                      dest_row, selection_data))
7586             gtk_tree_path_up (dest_row);
7587         }
7588     }
7589
7590   if (selection_data->length >= 0)
7591     {
7592       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7593                                                  dest_row,
7594                                                  selection_data))
7595         accepted = TRUE;
7596     }
7597
7598   gtk_drag_finish (context,
7599                    accepted,
7600                    (context->action == GDK_ACTION_MOVE),
7601                    time);
7602
7603   if (gtk_tree_path_get_depth (dest_row) == 1
7604       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7605     {
7606       /* special special case drag to "0", scroll to first item */
7607       if (!tree_view->priv->scroll_to_path)
7608         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7609     }
7610
7611   gtk_tree_path_free (dest_row);
7612
7613   /* drop dest_row */
7614   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7615 }
7616
7617
7618
7619 /* GtkContainer Methods
7620  */
7621
7622
7623 static void
7624 gtk_tree_view_remove (GtkContainer *container,
7625                       GtkWidget    *widget)
7626 {
7627   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7628   GtkTreeViewChild *child = NULL;
7629   GList *tmp_list;
7630
7631   tmp_list = tree_view->priv->children;
7632   while (tmp_list)
7633     {
7634       child = tmp_list->data;
7635       if (child->widget == widget)
7636         {
7637           gtk_widget_unparent (widget);
7638
7639           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7640           g_list_free_1 (tmp_list);
7641           g_slice_free (GtkTreeViewChild, child);
7642           return;
7643         }
7644
7645       tmp_list = tmp_list->next;
7646     }
7647
7648   tmp_list = tree_view->priv->columns;
7649
7650   while (tmp_list)
7651     {
7652       GtkTreeViewColumn *column;
7653       column = tmp_list->data;
7654       if (column->button == widget)
7655         {
7656           gtk_widget_unparent (widget);
7657           return;
7658         }
7659       tmp_list = tmp_list->next;
7660     }
7661 }
7662
7663 static void
7664 gtk_tree_view_forall (GtkContainer *container,
7665                       gboolean      include_internals,
7666                       GtkCallback   callback,
7667                       gpointer      callback_data)
7668 {
7669   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7670   GtkTreeViewChild *child = NULL;
7671   GtkTreeViewColumn *column;
7672   GList *tmp_list;
7673
7674   tmp_list = tree_view->priv->children;
7675   while (tmp_list)
7676     {
7677       child = tmp_list->data;
7678       tmp_list = tmp_list->next;
7679
7680       (* callback) (child->widget, callback_data);
7681     }
7682   if (include_internals == FALSE)
7683     return;
7684
7685   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7686     {
7687       column = tmp_list->data;
7688
7689       if (column->button)
7690         (* callback) (column->button, callback_data);
7691     }
7692 }
7693
7694 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7695  * cells. If so we draw one big row-spanning focus rectangle.
7696  */
7697 static gboolean
7698 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7699 {
7700   GList *list;
7701
7702   for (list = tree_view->priv->columns; list; list = list->next)
7703     {
7704       if (!((GtkTreeViewColumn *)list->data)->visible)
7705         continue;
7706       if (_gtk_tree_view_column_count_special_cells (list->data))
7707         return TRUE;
7708     }
7709
7710   return FALSE;
7711 }
7712
7713 static void
7714 column_sizing_notify (GObject    *object,
7715                       GParamSpec *pspec,
7716                       gpointer    data)
7717 {
7718   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7719
7720   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7721     /* disable fixed height mode */
7722     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7723 }
7724
7725 /**
7726  * gtk_tree_view_set_fixed_height_mode:
7727  * @tree_view: a #GtkTreeView 
7728  * @enable: %TRUE to enable fixed height mode
7729  * 
7730  * Enables or disables the fixed height mode of @tree_view. 
7731  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7732  * rows have the same height. 
7733  * Only enable this option if all rows are the same height and all
7734  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7735  *
7736  * Since: 2.6 
7737  **/
7738 void
7739 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7740                                      gboolean     enable)
7741 {
7742   GList *l;
7743   
7744   enable = enable != FALSE;
7745
7746   if (enable == tree_view->priv->fixed_height_mode)
7747     return;
7748
7749   if (!enable)
7750     {
7751       tree_view->priv->fixed_height_mode = 0;
7752       tree_view->priv->fixed_height = -1;
7753
7754       /* force a revalidation */
7755       install_presize_handler (tree_view);
7756     }
7757   else 
7758     {
7759       /* make sure all columns are of type FIXED */
7760       for (l = tree_view->priv->columns; l; l = l->next)
7761         {
7762           GtkTreeViewColumn *c = l->data;
7763           
7764           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7765         }
7766       
7767       /* yes, we really have to do this is in a separate loop */
7768       for (l = tree_view->priv->columns; l; l = l->next)
7769         g_signal_connect (l->data, "notify::sizing",
7770                           G_CALLBACK (column_sizing_notify), tree_view);
7771       
7772       tree_view->priv->fixed_height_mode = 1;
7773       tree_view->priv->fixed_height = -1;
7774       
7775       if (tree_view->priv->tree)
7776         initialize_fixed_height_mode (tree_view);
7777     }
7778
7779   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7780 }
7781
7782 /**
7783  * gtk_tree_view_get_fixed_height_mode:
7784  * @tree_view: a #GtkTreeView
7785  * 
7786  * Returns whether fixed height mode is turned on for @tree_view.
7787  * 
7788  * Return value: %TRUE if @tree_view is in fixed height mode
7789  * 
7790  * Since: 2.6
7791  **/
7792 gboolean
7793 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7794 {
7795   return tree_view->priv->fixed_height_mode;
7796 }
7797
7798 /* Returns TRUE if the focus is within the headers, after the focus operation is
7799  * done
7800  */
7801 static gboolean
7802 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7803                             GtkDirectionType  dir,
7804                             gboolean          clamp_column_visible)
7805 {
7806   GtkWidget *focus_child;
7807
7808   GList *last_column, *first_column;
7809   GList *tmp_list;
7810   gboolean rtl;
7811
7812   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7813     return FALSE;
7814
7815   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7816
7817   first_column = tree_view->priv->columns;
7818   while (first_column)
7819     {
7820       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7821           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7822           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7823            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7824         break;
7825       first_column = first_column->next;
7826     }
7827
7828   /* No headers are visible, or are focusable.  We can't focus in or out.
7829    */
7830   if (first_column == NULL)
7831     return FALSE;
7832
7833   last_column = g_list_last (tree_view->priv->columns);
7834   while (last_column)
7835     {
7836       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7837           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7838           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7839            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7840         break;
7841       last_column = last_column->prev;
7842     }
7843
7844
7845   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7846
7847   switch (dir)
7848     {
7849     case GTK_DIR_TAB_BACKWARD:
7850     case GTK_DIR_TAB_FORWARD:
7851     case GTK_DIR_UP:
7852     case GTK_DIR_DOWN:
7853       if (focus_child == NULL)
7854         {
7855           if (tree_view->priv->focus_column != NULL &&
7856               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7857             focus_child = tree_view->priv->focus_column->button;
7858           else
7859             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7860           gtk_widget_grab_focus (focus_child);
7861           break;
7862         }
7863       return FALSE;
7864
7865     case GTK_DIR_LEFT:
7866     case GTK_DIR_RIGHT:
7867       if (focus_child == NULL)
7868         {
7869           if (tree_view->priv->focus_column != NULL)
7870             focus_child = tree_view->priv->focus_column->button;
7871           else if (dir == GTK_DIR_LEFT)
7872             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7873           else
7874             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7875           gtk_widget_grab_focus (focus_child);
7876           break;
7877         }
7878
7879       if (gtk_widget_child_focus (focus_child, dir))
7880         {
7881           /* The focus moves inside the button. */
7882           /* This is probably a great example of bad UI */
7883           break;
7884         }
7885
7886       /* We need to move the focus among the row of buttons. */
7887       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7888         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7889           break;
7890
7891       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7892           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7893         {
7894           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7895           break;
7896         }
7897
7898       while (tmp_list)
7899         {
7900           GtkTreeViewColumn *column;
7901
7902           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7903             tmp_list = tmp_list->next;
7904           else
7905             tmp_list = tmp_list->prev;
7906
7907           if (tmp_list == NULL)
7908             {
7909               g_warning ("Internal button not found");
7910               break;
7911             }
7912           column = tmp_list->data;
7913           if (column->button &&
7914               column->visible &&
7915               gtk_widget_get_can_focus (column->button))
7916             {
7917               focus_child = column->button;
7918               gtk_widget_grab_focus (column->button);
7919               break;
7920             }
7921         }
7922       break;
7923     default:
7924       g_assert_not_reached ();
7925       break;
7926     }
7927
7928   /* if focus child is non-null, we assume it's been set to the current focus child
7929    */
7930   if (focus_child)
7931     {
7932       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7933         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7934           {
7935             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7936             break;
7937           }
7938
7939       if (clamp_column_visible)
7940         {
7941           gtk_tree_view_clamp_column_visible (tree_view,
7942                                               tree_view->priv->focus_column,
7943                                               FALSE);
7944         }
7945     }
7946
7947   return (focus_child != NULL);
7948 }
7949
7950 /* This function returns in 'path' the first focusable path, if the given path
7951  * is already focusable, it's the returned one.
7952  */
7953 static gboolean
7954 search_first_focusable_path (GtkTreeView  *tree_view,
7955                              GtkTreePath **path,
7956                              gboolean      search_forward,
7957                              GtkRBTree   **new_tree,
7958                              GtkRBNode   **new_node)
7959 {
7960   GtkRBTree *tree = NULL;
7961   GtkRBNode *node = NULL;
7962
7963   if (!path || !*path)
7964     return FALSE;
7965
7966   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7967
7968   if (!tree || !node)
7969     return FALSE;
7970
7971   while (node && row_is_separator (tree_view, NULL, *path))
7972     {
7973       if (search_forward)
7974         _gtk_rbtree_next_full (tree, node, &tree, &node);
7975       else
7976         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7977
7978       if (*path)
7979         gtk_tree_path_free (*path);
7980
7981       if (node)
7982         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7983       else
7984         *path = NULL;
7985     }
7986
7987   if (new_tree)
7988     *new_tree = tree;
7989
7990   if (new_node)
7991     *new_node = node;
7992
7993   return (*path != NULL);
7994 }
7995
7996 static gint
7997 gtk_tree_view_focus (GtkWidget        *widget,
7998                      GtkDirectionType  direction)
7999 {
8000   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8001   GtkContainer *container = GTK_CONTAINER (widget);
8002   GtkWidget *focus_child;
8003
8004   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8005     return FALSE;
8006
8007   focus_child = gtk_container_get_focus_child (container);
8008
8009   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8010   /* Case 1.  Headers currently have focus. */
8011   if (focus_child)
8012     {
8013       switch (direction)
8014         {
8015         case GTK_DIR_LEFT:
8016         case GTK_DIR_RIGHT:
8017           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8018           return TRUE;
8019         case GTK_DIR_TAB_BACKWARD:
8020         case GTK_DIR_UP:
8021           return FALSE;
8022         case GTK_DIR_TAB_FORWARD:
8023         case GTK_DIR_DOWN:
8024           gtk_widget_grab_focus (widget);
8025           return TRUE;
8026         default:
8027           g_assert_not_reached ();
8028           return FALSE;
8029         }
8030     }
8031
8032   /* Case 2. We don't have focus at all. */
8033   if (!gtk_widget_has_focus (widget))
8034     {
8035       gtk_widget_grab_focus (widget);
8036       return TRUE;
8037     }
8038
8039   /* Case 3. We have focus already. */
8040   if (direction == GTK_DIR_TAB_BACKWARD)
8041     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8042   else if (direction == GTK_DIR_TAB_FORWARD)
8043     return FALSE;
8044
8045   /* Other directions caught by the keybindings */
8046   gtk_widget_grab_focus (widget);
8047   return TRUE;
8048 }
8049
8050 static void
8051 gtk_tree_view_grab_focus (GtkWidget *widget)
8052 {
8053   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8054
8055   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8056 }
8057
8058 static void
8059 gtk_tree_view_style_set (GtkWidget *widget,
8060                          GtkStyle *previous_style)
8061 {
8062   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8063   GtkStyle *style;
8064   GList *list;
8065   GtkTreeViewColumn *column;
8066
8067   if (gtk_widget_get_realized (widget))
8068     {
8069       style = gtk_widget_get_style (widget);
8070       gdk_window_set_background (tree_view->priv->bin_window,
8071                                  &style->base[gtk_widget_get_state (widget)]);
8072       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8073
8074       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8075       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8076     }
8077
8078   gtk_widget_style_get (widget,
8079                         "expander-size", &tree_view->priv->expander_size,
8080                         NULL);
8081   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8082
8083   for (list = tree_view->priv->columns; list; list = list->next)
8084     {
8085       column = list->data;
8086       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8087     }
8088
8089   tree_view->priv->fixed_height = -1;
8090   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8091
8092   gtk_widget_queue_resize (widget);
8093 }
8094
8095
8096 static void
8097 gtk_tree_view_set_focus_child (GtkContainer *container,
8098                                GtkWidget    *child)
8099 {
8100   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8101   GList *list;
8102
8103   for (list = tree_view->priv->columns; list; list = list->next)
8104     {
8105       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8106         {
8107           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8108           break;
8109         }
8110     }
8111
8112   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8113 }
8114
8115 static void
8116 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
8117                                GtkAdjustment *hadj,
8118                                GtkAdjustment *vadj)
8119 {
8120   gboolean need_adjust = FALSE;
8121
8122   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8123
8124   if (hadj)
8125     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
8126   else
8127     hadj = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
8128   if (vadj)
8129     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
8130   else
8131     vadj = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
8132
8133   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8134     {
8135       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8136                                             gtk_tree_view_adjustment_changed,
8137                                             tree_view);
8138       g_object_unref (tree_view->priv->hadjustment);
8139     }
8140
8141   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8142     {
8143       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8144                                             gtk_tree_view_adjustment_changed,
8145                                             tree_view);
8146       g_object_unref (tree_view->priv->vadjustment);
8147     }
8148
8149   if (tree_view->priv->hadjustment != hadj)
8150     {
8151       tree_view->priv->hadjustment = hadj;
8152       g_object_ref_sink (tree_view->priv->hadjustment);
8153
8154       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8155                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8156                         tree_view);
8157       need_adjust = TRUE;
8158     }
8159
8160   if (tree_view->priv->vadjustment != vadj)
8161     {
8162       tree_view->priv->vadjustment = vadj;
8163       g_object_ref_sink (tree_view->priv->vadjustment);
8164
8165       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8166                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8167                         tree_view);
8168       need_adjust = TRUE;
8169     }
8170
8171   if (need_adjust)
8172     gtk_tree_view_adjustment_changed (NULL, tree_view);
8173 }
8174
8175
8176 static gboolean
8177 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8178                                 GtkMovementStep    step,
8179                                 gint               count)
8180 {
8181   GdkModifierType state;
8182
8183   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8184   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8185                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8186                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8187                         step == GTK_MOVEMENT_PAGES ||
8188                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8189
8190   if (tree_view->priv->tree == NULL)
8191     return FALSE;
8192   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8193     return FALSE;
8194
8195   gtk_tree_view_stop_editing (tree_view, FALSE);
8196   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8197   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8198
8199   if (gtk_get_current_event_state (&state))
8200     {
8201       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8202         tree_view->priv->ctrl_pressed = TRUE;
8203       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8204         tree_view->priv->shift_pressed = TRUE;
8205     }
8206   /* else we assume not pressed */
8207
8208   switch (step)
8209     {
8210       /* currently we make no distinction.  When we go bi-di, we need to */
8211     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8212     case GTK_MOVEMENT_VISUAL_POSITIONS:
8213       gtk_tree_view_move_cursor_left_right (tree_view, count);
8214       break;
8215     case GTK_MOVEMENT_DISPLAY_LINES:
8216       gtk_tree_view_move_cursor_up_down (tree_view, count);
8217       break;
8218     case GTK_MOVEMENT_PAGES:
8219       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8220       break;
8221     case GTK_MOVEMENT_BUFFER_ENDS:
8222       gtk_tree_view_move_cursor_start_end (tree_view, count);
8223       break;
8224     default:
8225       g_assert_not_reached ();
8226     }
8227
8228   tree_view->priv->ctrl_pressed = FALSE;
8229   tree_view->priv->shift_pressed = FALSE;
8230
8231   return TRUE;
8232 }
8233
8234 static void
8235 gtk_tree_view_put (GtkTreeView *tree_view,
8236                    GtkWidget   *child_widget,
8237                    /* in bin_window coordinates */
8238                    gint         x,
8239                    gint         y,
8240                    gint         width,
8241                    gint         height)
8242 {
8243   GtkTreeViewChild *child;
8244   
8245   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8246   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8247
8248   child = g_slice_new (GtkTreeViewChild);
8249
8250   child->widget = child_widget;
8251   child->x = x;
8252   child->y = y;
8253   child->width = width;
8254   child->height = height;
8255
8256   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8257
8258   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8259     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8260   
8261   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8262 }
8263
8264 void
8265 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8266                                   GtkWidget   *widget,
8267                                   /* in tree coordinates */
8268                                   gint         x,
8269                                   gint         y,
8270                                   gint         width,
8271                                   gint         height)
8272 {
8273   GtkTreeViewChild *child = NULL;
8274   GList *list;
8275   GdkRectangle allocation;
8276
8277   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8278   g_return_if_fail (GTK_IS_WIDGET (widget));
8279
8280   for (list = tree_view->priv->children; list; list = list->next)
8281     {
8282       if (((GtkTreeViewChild *)list->data)->widget == widget)
8283         {
8284           child = list->data;
8285           break;
8286         }
8287     }
8288   if (child == NULL)
8289     return;
8290
8291   allocation.x = child->x = x;
8292   allocation.y = child->y = y;
8293   allocation.width = child->width = width;
8294   allocation.height = child->height = height;
8295
8296   if (gtk_widget_get_realized (widget))
8297     gtk_widget_size_allocate (widget, &allocation);
8298 }
8299
8300
8301 /* TreeModel Callbacks
8302  */
8303
8304 static void
8305 gtk_tree_view_row_changed (GtkTreeModel *model,
8306                            GtkTreePath  *path,
8307                            GtkTreeIter  *iter,
8308                            gpointer      data)
8309 {
8310   GtkTreeView *tree_view = (GtkTreeView *)data;
8311   GtkRBTree *tree;
8312   GtkRBNode *node;
8313   gboolean free_path = FALSE;
8314   GList *list;
8315   GtkTreePath *cursor_path;
8316
8317   g_return_if_fail (path != NULL || iter != NULL);
8318
8319   if (tree_view->priv->cursor != NULL)
8320     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8321   else
8322     cursor_path = NULL;
8323
8324   if (tree_view->priv->edited_column &&
8325       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8326     gtk_tree_view_stop_editing (tree_view, TRUE);
8327
8328   if (cursor_path != NULL)
8329     gtk_tree_path_free (cursor_path);
8330
8331   if (path == NULL)
8332     {
8333       path = gtk_tree_model_get_path (model, iter);
8334       free_path = TRUE;
8335     }
8336   else if (iter == NULL)
8337     gtk_tree_model_get_iter (model, iter, path);
8338
8339   if (_gtk_tree_view_find_node (tree_view,
8340                                 path,
8341                                 &tree,
8342                                 &node))
8343     /* We aren't actually showing the node */
8344     goto done;
8345
8346   if (tree == NULL)
8347     goto done;
8348
8349   if (tree_view->priv->fixed_height_mode
8350       && tree_view->priv->fixed_height >= 0)
8351     {
8352       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8353       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8354         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8355     }
8356   else
8357     {
8358       _gtk_rbtree_node_mark_invalid (tree, node);
8359       for (list = tree_view->priv->columns; list; list = list->next)
8360         {
8361           GtkTreeViewColumn *column;
8362
8363           column = list->data;
8364           if (! column->visible)
8365             continue;
8366
8367           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8368             {
8369               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8370             }
8371         }
8372     }
8373
8374  done:
8375   if (!tree_view->priv->fixed_height_mode &&
8376       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8377     install_presize_handler (tree_view);
8378   if (free_path)
8379     gtk_tree_path_free (path);
8380 }
8381
8382 static void
8383 gtk_tree_view_row_inserted (GtkTreeModel *model,
8384                             GtkTreePath  *path,
8385                             GtkTreeIter  *iter,
8386                             gpointer      data)
8387 {
8388   GtkTreeView *tree_view = (GtkTreeView *) data;
8389   gint *indices;
8390   GtkRBTree *tmptree, *tree;
8391   GtkRBNode *tmpnode = NULL;
8392   gint depth;
8393   gint i = 0;
8394   gint height;
8395   gboolean free_path = FALSE;
8396   gboolean node_visible = TRUE;
8397
8398   g_return_if_fail (path != NULL || iter != NULL);
8399
8400   if (tree_view->priv->fixed_height_mode
8401       && tree_view->priv->fixed_height >= 0)
8402     height = tree_view->priv->fixed_height;
8403   else
8404     height = 0;
8405
8406   if (path == NULL)
8407     {
8408       path = gtk_tree_model_get_path (model, iter);
8409       free_path = TRUE;
8410     }
8411   else if (iter == NULL)
8412     gtk_tree_model_get_iter (model, iter, path);
8413
8414   if (tree_view->priv->tree == NULL)
8415     tree_view->priv->tree = _gtk_rbtree_new ();
8416
8417   tmptree = tree = tree_view->priv->tree;
8418
8419   /* Update all row-references */
8420   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8421   depth = gtk_tree_path_get_depth (path);
8422   indices = gtk_tree_path_get_indices (path);
8423
8424   /* First, find the parent tree */
8425   while (i < depth - 1)
8426     {
8427       if (tmptree == NULL)
8428         {
8429           /* We aren't showing the node */
8430           node_visible = FALSE;
8431           goto done;
8432         }
8433
8434       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8435       if (tmpnode == NULL)
8436         {
8437           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8438                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8439                      "before the parent was inserted.");
8440           goto done;
8441         }
8442       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8443         {
8444           /* FIXME enforce correct behavior on model, probably */
8445           /* In theory, the model should have emitted has_child_toggled here.  We
8446            * try to catch it anyway, just to be safe, in case the model hasn't.
8447            */
8448           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8449                                                            tree,
8450                                                            tmpnode);
8451           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8452           gtk_tree_path_free (tmppath);
8453           goto done;
8454         }
8455
8456       tmptree = tmpnode->children;
8457       tree = tmptree;
8458       i++;
8459     }
8460
8461   if (tree == NULL)
8462     {
8463       node_visible = FALSE;
8464       goto done;
8465     }
8466
8467   /* ref the node */
8468   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8469   if (indices[depth - 1] == 0)
8470     {
8471       tmpnode = _gtk_rbtree_find_count (tree, 1);
8472       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8473     }
8474   else
8475     {
8476       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8477       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8478     }
8479
8480  done:
8481   if (height > 0)
8482     {
8483       if (tree)
8484         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8485
8486       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8487         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8488       else
8489         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8490     }
8491   else
8492     install_presize_handler (tree_view);
8493   if (free_path)
8494     gtk_tree_path_free (path);
8495 }
8496
8497 static void
8498 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8499                                      GtkTreePath  *path,
8500                                      GtkTreeIter  *iter,
8501                                      gpointer      data)
8502 {
8503   GtkTreeView *tree_view = (GtkTreeView *)data;
8504   GtkTreeIter real_iter;
8505   gboolean has_child;
8506   GtkRBTree *tree;
8507   GtkRBNode *node;
8508   gboolean free_path = FALSE;
8509
8510   g_return_if_fail (path != NULL || iter != NULL);
8511
8512   if (iter)
8513     real_iter = *iter;
8514
8515   if (path == NULL)
8516     {
8517       path = gtk_tree_model_get_path (model, iter);
8518       free_path = TRUE;
8519     }
8520   else if (iter == NULL)
8521     gtk_tree_model_get_iter (model, &real_iter, path);
8522
8523   if (_gtk_tree_view_find_node (tree_view,
8524                                 path,
8525                                 &tree,
8526                                 &node))
8527     /* We aren't actually showing the node */
8528     goto done;
8529
8530   if (tree == NULL)
8531     goto done;
8532
8533   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8534   /* Sanity check.
8535    */
8536   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8537     goto done;
8538
8539   if (has_child)
8540     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8541   else
8542     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8543
8544   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8545     {
8546       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8547       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8548         {
8549           GList *list;
8550
8551           for (list = tree_view->priv->columns; list; list = list->next)
8552             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8553               {
8554                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8555                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8556                 break;
8557               }
8558         }
8559       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8560     }
8561   else
8562     {
8563       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8564     }
8565
8566  done:
8567   if (free_path)
8568     gtk_tree_path_free (path);
8569 }
8570
8571 static void
8572 count_children_helper (GtkRBTree *tree,
8573                        GtkRBNode *node,
8574                        gpointer   data)
8575 {
8576   if (node->children)
8577     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8578   (*((gint *)data))++;
8579 }
8580
8581 static void
8582 check_selection_helper (GtkRBTree *tree,
8583                         GtkRBNode *node,
8584                         gpointer   data)
8585 {
8586   gint *value = (gint *)data;
8587
8588   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8589
8590   if (node->children && !*value)
8591     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8592 }
8593
8594 static void
8595 gtk_tree_view_row_deleted (GtkTreeModel *model,
8596                            GtkTreePath  *path,
8597                            gpointer      data)
8598 {
8599   GtkTreeView *tree_view = (GtkTreeView *)data;
8600   GtkRBTree *tree;
8601   GtkRBNode *node;
8602   GList *list;
8603   gint selection_changed = FALSE;
8604
8605   g_return_if_fail (path != NULL);
8606
8607   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8608
8609   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8610     return;
8611
8612   if (tree == NULL)
8613     return;
8614
8615   /* check if the selection has been changed */
8616   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8617                         check_selection_helper, &selection_changed);
8618
8619   for (list = tree_view->priv->columns; list; list = list->next)
8620     if (((GtkTreeViewColumn *)list->data)->visible &&
8621         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8622       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8623
8624   /* Ensure we don't have a dangling pointer to a dead node */
8625   ensure_unprelighted (tree_view);
8626
8627   /* Cancel editting if we've started */
8628   gtk_tree_view_stop_editing (tree_view, TRUE);
8629
8630   /* If we have a node expanded/collapsed timeout, remove it */
8631   remove_expand_collapse_timeout (tree_view);
8632
8633   if (tree_view->priv->destroy_count_func)
8634     {
8635       gint child_count = 0;
8636       if (node->children)
8637         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8638       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8639     }
8640
8641   if (tree->root->count == 1)
8642     {
8643       if (tree_view->priv->tree == tree)
8644         tree_view->priv->tree = NULL;
8645
8646       _gtk_rbtree_remove (tree);
8647     }
8648   else
8649     {
8650       _gtk_rbtree_remove_node (tree, node);
8651     }
8652
8653   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8654     {
8655       gtk_tree_row_reference_free (tree_view->priv->top_row);
8656       tree_view->priv->top_row = NULL;
8657     }
8658
8659   install_scroll_sync_handler (tree_view);
8660
8661   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8662
8663   if (selection_changed)
8664     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8665 }
8666
8667 static void
8668 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8669                               GtkTreePath  *parent,
8670                               GtkTreeIter  *iter,
8671                               gint         *new_order,
8672                               gpointer      data)
8673 {
8674   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8675   GtkRBTree *tree;
8676   GtkRBNode *node;
8677   gint len;
8678
8679   len = gtk_tree_model_iter_n_children (model, iter);
8680
8681   if (len < 2)
8682     return;
8683
8684   gtk_tree_row_reference_reordered (G_OBJECT (data),
8685                                     parent,
8686                                     iter,
8687                                     new_order);
8688
8689   if (_gtk_tree_view_find_node (tree_view,
8690                                 parent,
8691                                 &tree,
8692                                 &node))
8693     return;
8694
8695   /* We need to special case the parent path */
8696   if (tree == NULL)
8697     tree = tree_view->priv->tree;
8698   else
8699     tree = node->children;
8700
8701   if (tree == NULL)
8702     return;
8703
8704   if (tree_view->priv->edited_column)
8705     gtk_tree_view_stop_editing (tree_view, TRUE);
8706
8707   /* we need to be unprelighted */
8708   ensure_unprelighted (tree_view);
8709
8710   /* clear the timeout */
8711   cancel_arrow_animation (tree_view);
8712   
8713   _gtk_rbtree_reorder (tree, new_order, len);
8714
8715   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8716
8717   gtk_tree_view_dy_to_top_row (tree_view);
8718 }
8719
8720
8721 /* Internal tree functions
8722  */
8723
8724
8725 static void
8726 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8727                                      GtkRBTree         *tree,
8728                                      GtkTreeViewColumn *column,
8729                                      gint              *x1,
8730                                      gint              *x2)
8731 {
8732   GtkTreeViewColumn *tmp_column = NULL;
8733   gint total_width;
8734   GList *list;
8735   gboolean rtl;
8736
8737   if (x1)
8738     *x1 = 0;
8739
8740   if (x2)
8741     *x2 = 0;
8742
8743   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8744
8745   total_width = 0;
8746   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8747        list;
8748        list = (rtl ? list->prev : list->next))
8749     {
8750       tmp_column = list->data;
8751
8752       if (tmp_column == column)
8753         break;
8754
8755       if (tmp_column->visible)
8756         total_width += tmp_column->width;
8757     }
8758
8759   if (tmp_column != column)
8760     {
8761       g_warning (G_STRLOC": passed-in column isn't in the tree");
8762       return;
8763     }
8764
8765   if (x1)
8766     *x1 = total_width;
8767
8768   if (x2)
8769     {
8770       if (column->visible)
8771         *x2 = total_width + column->width;
8772       else
8773         *x2 = total_width; /* width of 0 */
8774     }
8775 }
8776 static void
8777 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8778                                 GtkRBTree   *tree,
8779                                 gint        *x1,
8780                                 gint        *x2)
8781 {
8782   gint x_offset = 0;
8783   GList *list;
8784   GtkTreeViewColumn *tmp_column = NULL;
8785   gint total_width;
8786   gboolean indent_expanders;
8787   gboolean rtl;
8788
8789   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8790
8791   total_width = 0;
8792   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8793        list;
8794        list = (rtl ? list->prev : list->next))
8795     {
8796       tmp_column = list->data;
8797
8798       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8799         {
8800           if (rtl)
8801             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8802           else
8803             x_offset = total_width;
8804           break;
8805         }
8806
8807       if (tmp_column->visible)
8808         total_width += tmp_column->width;
8809     }
8810
8811   gtk_widget_style_get (GTK_WIDGET (tree_view),
8812                         "indent-expanders", &indent_expanders,
8813                         NULL);
8814
8815   if (indent_expanders)
8816     {
8817       if (rtl)
8818         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8819       else
8820         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8821     }
8822
8823   *x1 = x_offset;
8824   
8825   if (tmp_column && tmp_column->visible)
8826     /* +1 because x2 isn't included in the range. */
8827     *x2 = *x1 + tree_view->priv->expander_size + 1;
8828   else
8829     *x2 = *x1;
8830 }
8831
8832 static void
8833 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8834                           GtkRBTree   *tree,
8835                           GtkTreeIter *iter,
8836                           gint         depth,
8837                           gboolean     recurse)
8838 {
8839   GtkRBNode *temp = NULL;
8840   GtkTreePath *path = NULL;
8841   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8842
8843   do
8844     {
8845       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8846       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8847
8848       if (tree_view->priv->fixed_height > 0)
8849         {
8850           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8851             {
8852               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8853               _gtk_rbtree_node_mark_valid (tree, temp);
8854             }
8855         }
8856
8857       if (is_list)
8858         continue;
8859
8860       if (recurse)
8861         {
8862           GtkTreeIter child;
8863
8864           if (!path)
8865             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8866           else
8867             gtk_tree_path_next (path);
8868
8869           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8870             {
8871               gboolean expand;
8872
8873               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8874
8875               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8876                   && !expand)
8877                 {
8878                   temp->children = _gtk_rbtree_new ();
8879                   temp->children->parent_tree = tree;
8880                   temp->children->parent_node = temp;
8881                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8882                 }
8883             }
8884         }
8885
8886       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8887         {
8888           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8889             temp->flags ^= GTK_RBNODE_IS_PARENT;
8890         }
8891     }
8892   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8893
8894   if (path)
8895     gtk_tree_path_free (path);
8896 }
8897
8898 /* Make sure the node is visible vertically */
8899 static void
8900 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8901                                   GtkRBTree   *tree,
8902                                   GtkRBNode   *node)
8903 {
8904   gint node_dy, height;
8905   GtkTreePath *path = NULL;
8906
8907   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8908     return;
8909
8910   /* just return if the node is visible, avoiding a costly expose */
8911   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8912   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8913   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8914       && node_dy >= tree_view->priv->vadjustment->value
8915       && node_dy + height <= (tree_view->priv->vadjustment->value
8916                               + tree_view->priv->vadjustment->page_size))
8917     return;
8918
8919   path = _gtk_tree_view_find_path (tree_view, tree, node);
8920   if (path)
8921     {
8922       /* We process updates because we want to clear old selected items when we scroll.
8923        * if this is removed, we get a "selection streak" at the bottom. */
8924       gtk_tree_view_bin_process_updates (tree_view);
8925
8926       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8927       gtk_tree_path_free (path);
8928     }
8929 }
8930
8931 static void
8932 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8933                                     GtkTreeViewColumn *column,
8934                                     gboolean           focus_to_cell)
8935 {
8936   GtkAllocation allocation;
8937   gint x, width;
8938
8939   if (column == NULL)
8940     return;
8941
8942   gtk_widget_get_allocation (column->button, &allocation);
8943   x = allocation.x;
8944   width = allocation.width;
8945
8946   if (width > tree_view->priv->hadjustment->page_size)
8947     {
8948       /* The column is larger than the horizontal page size.  If the
8949        * column has cells which can be focussed individually, then we make
8950        * sure the cell which gets focus is fully visible (if even the
8951        * focus cell is bigger than the page size, we make sure the
8952        * left-hand side of the cell is visible).
8953        *
8954        * If the column does not have those so-called special cells, we
8955        * make sure the left-hand side of the column is visible.
8956        */
8957
8958       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8959         {
8960           GtkTreePath *cursor_path;
8961           GdkRectangle background_area, cell_area, focus_area;
8962
8963           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8964
8965           gtk_tree_view_get_cell_area (tree_view,
8966                                        cursor_path, column, &cell_area);
8967           gtk_tree_view_get_background_area (tree_view,
8968                                              cursor_path, column,
8969                                              &background_area);
8970
8971           gtk_tree_path_free (cursor_path);
8972
8973           _gtk_tree_view_column_get_focus_area (column,
8974                                                 &background_area,
8975                                                 &cell_area,
8976                                                 &focus_area);
8977
8978           x = focus_area.x;
8979           width = focus_area.width;
8980
8981           if (width < tree_view->priv->hadjustment->page_size)
8982             {
8983               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8984                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8985                                           x + width - tree_view->priv->hadjustment->page_size);
8986               else if (tree_view->priv->hadjustment->value > x)
8987                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8988             }
8989         }
8990
8991       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8992     }
8993   else
8994     {
8995       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8996           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8997                                     x + width - tree_view->priv->hadjustment->page_size);
8998       else if (tree_view->priv->hadjustment->value > x)
8999         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9000   }
9001 }
9002
9003 /* This function could be more efficient.  I'll optimize it if profiling seems
9004  * to imply that it is important */
9005 GtkTreePath *
9006 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9007                           GtkRBTree   *tree,
9008                           GtkRBNode   *node)
9009 {
9010   GtkTreePath *path;
9011   GtkRBTree *tmp_tree;
9012   GtkRBNode *tmp_node, *last;
9013   gint count;
9014
9015   path = gtk_tree_path_new ();
9016
9017   g_return_val_if_fail (node != NULL, path);
9018   g_return_val_if_fail (node != tree->nil, path);
9019
9020   count = 1 + node->left->count;
9021
9022   last = node;
9023   tmp_node = node->parent;
9024   tmp_tree = tree;
9025   while (tmp_tree)
9026     {
9027       while (tmp_node != tmp_tree->nil)
9028         {
9029           if (tmp_node->right == last)
9030             count += 1 + tmp_node->left->count;
9031           last = tmp_node;
9032           tmp_node = tmp_node->parent;
9033         }
9034       gtk_tree_path_prepend_index (path, count - 1);
9035       last = tmp_tree->parent_node;
9036       tmp_tree = tmp_tree->parent_tree;
9037       if (last)
9038         {
9039           count = 1 + last->left->count;
9040           tmp_node = last->parent;
9041         }
9042     }
9043   return path;
9044 }
9045
9046 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9047  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9048  * both set to NULL.
9049  */
9050 gboolean
9051 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9052                           GtkTreePath  *path,
9053                           GtkRBTree   **tree,
9054                           GtkRBNode   **node)
9055 {
9056   GtkRBNode *tmpnode = NULL;
9057   GtkRBTree *tmptree = tree_view->priv->tree;
9058   gint *indices = gtk_tree_path_get_indices (path);
9059   gint depth = gtk_tree_path_get_depth (path);
9060   gint i = 0;
9061
9062   *node = NULL;
9063   *tree = NULL;
9064
9065   if (depth == 0 || tmptree == NULL)
9066     return FALSE;
9067   do
9068     {
9069       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9070       ++i;
9071       if (tmpnode == NULL)
9072         {
9073           *tree = NULL;
9074           *node = NULL;
9075           return FALSE;
9076         }
9077       if (i >= depth)
9078         {
9079           *tree = tmptree;
9080           *node = tmpnode;
9081           return FALSE;
9082         }
9083       *tree = tmptree;
9084       *node = tmpnode;
9085       tmptree = tmpnode->children;
9086       if (tmptree == NULL)
9087         return TRUE;
9088     }
9089   while (1);
9090 }
9091
9092 static gboolean
9093 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9094                                   GtkTreeViewColumn *column)
9095 {
9096   GList *list;
9097
9098   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9099     return FALSE;
9100
9101   if (tree_view->priv->expander_column != NULL)
9102     {
9103       if (tree_view->priv->expander_column == column)
9104         return TRUE;
9105       return FALSE;
9106     }
9107   else
9108     {
9109       for (list = tree_view->priv->columns;
9110            list;
9111            list = list->next)
9112         if (((GtkTreeViewColumn *)list->data)->visible)
9113           break;
9114       if (list && list->data == column)
9115         return TRUE;
9116     }
9117   return FALSE;
9118 }
9119
9120 static void
9121 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9122                                 guint           keyval,
9123                                 guint           modmask,
9124                                 gboolean        add_shifted_binding,
9125                                 GtkMovementStep step,
9126                                 gint            count)
9127 {
9128   
9129   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9130                                 "move-cursor", 2,
9131                                 G_TYPE_ENUM, step,
9132                                 G_TYPE_INT, count);
9133
9134   if (add_shifted_binding)
9135     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9136                                   "move-cursor", 2,
9137                                   G_TYPE_ENUM, step,
9138                                   G_TYPE_INT, count);
9139
9140   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9141    return;
9142
9143   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9144                                 "move-cursor", 2,
9145                                 G_TYPE_ENUM, step,
9146                                 G_TYPE_INT, count);
9147
9148   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9149                                 "move-cursor", 2,
9150                                 G_TYPE_ENUM, step,
9151                                 G_TYPE_INT, count);
9152 }
9153
9154 static gint
9155 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9156                                  GtkTreeIter  *iter,
9157                                  GtkRBTree    *tree,
9158                                  GtkRBNode    *node)
9159 {
9160   gint retval = FALSE;
9161   do
9162     {
9163       g_return_val_if_fail (node != NULL, FALSE);
9164
9165       if (node->children)
9166         {
9167           GtkTreeIter child;
9168           GtkRBTree *new_tree;
9169           GtkRBNode *new_node;
9170
9171           new_tree = node->children;
9172           new_node = new_tree->root;
9173
9174           while (new_node && new_node->left != new_tree->nil)
9175             new_node = new_node->left;
9176
9177           if (!gtk_tree_model_iter_children (model, &child, iter))
9178             return FALSE;
9179
9180           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9181         }
9182
9183       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9184         retval = TRUE;
9185       gtk_tree_model_unref_node (model, iter);
9186       node = _gtk_rbtree_next (tree, node);
9187     }
9188   while (gtk_tree_model_iter_next (model, iter));
9189
9190   return retval;
9191 }
9192
9193 static gint
9194 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9195                                               GtkRBTree   *tree)
9196 {
9197   GtkTreeIter iter;
9198   GtkTreePath *path;
9199   GtkRBNode *node;
9200   gint retval;
9201
9202   if (!tree)
9203     return FALSE;
9204
9205   node = tree->root;
9206   while (node && node->left != tree->nil)
9207     node = node->left;
9208
9209   g_return_val_if_fail (node != NULL, FALSE);
9210   path = _gtk_tree_view_find_path (tree_view, tree, node);
9211   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9212                            &iter, path);
9213   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9214   gtk_tree_path_free (path);
9215
9216   return retval;
9217 }
9218
9219 static void
9220 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9221                                     GtkTreeViewColumn *column)
9222 {
9223   GtkTreeViewColumn *left_column;
9224   GtkTreeViewColumn *cur_column = NULL;
9225   GtkTreeViewColumnReorder *reorder;
9226   gboolean rtl;
9227   GList *tmp_list;
9228   gint left;
9229
9230   /* We want to precalculate the motion list such that we know what column slots
9231    * are available.
9232    */
9233   left_column = NULL;
9234   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9235
9236   /* First, identify all possible drop spots */
9237   if (rtl)
9238     tmp_list = g_list_last (tree_view->priv->columns);
9239   else
9240     tmp_list = g_list_first (tree_view->priv->columns);
9241
9242   while (tmp_list)
9243     {
9244       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9245       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9246
9247       if (cur_column->visible == FALSE)
9248         continue;
9249
9250       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9251       if (left_column != column && cur_column != column &&
9252           tree_view->priv->column_drop_func &&
9253           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9254         {
9255           left_column = cur_column;
9256           continue;
9257         }
9258       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9259       reorder->left_column = left_column;
9260       left_column = reorder->right_column = cur_column;
9261
9262       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9263     }
9264
9265   /* Add the last one */
9266   if (tree_view->priv->column_drop_func == NULL ||
9267       ((left_column != column) &&
9268        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9269     {
9270       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9271       reorder->left_column = left_column;
9272       reorder->right_column = NULL;
9273       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9274     }
9275
9276   /* We quickly check to see if it even makes sense to reorder columns. */
9277   /* If there is nothing that can be moved, then we return */
9278
9279   if (tree_view->priv->column_drag_info == NULL)
9280     return;
9281
9282   /* We know there are always 2 slots possbile, as you can always return column. */
9283   /* If that's all there is, return */
9284   if (tree_view->priv->column_drag_info->next == NULL || 
9285       (tree_view->priv->column_drag_info->next->next == NULL &&
9286        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9287        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9288     {
9289       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9290         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9291       g_list_free (tree_view->priv->column_drag_info);
9292       tree_view->priv->column_drag_info = NULL;
9293       return;
9294     }
9295   /* We fill in the ranges for the columns, now that we've isolated them */
9296   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9297
9298   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9299     {
9300       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9301
9302       reorder->left_align = left;
9303       if (tmp_list->next != NULL)
9304         {
9305           GtkAllocation right_allocation, left_allocation;
9306
9307           g_assert (tmp_list->next->data);
9308
9309           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9310           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9311           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9312         }
9313       else
9314         {
9315           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9316                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9317         }
9318     }
9319 }
9320
9321 void
9322 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9323                                   GtkTreeViewColumn *column,
9324                                   GdkDevice         *device)
9325 {
9326   GdkEvent *send_event;
9327   GtkAllocation allocation;
9328   GtkAllocation button_allocation;
9329   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9330   GdkDisplay *display = gdk_screen_get_display (screen);
9331
9332   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9333   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9334
9335   gtk_tree_view_set_column_drag_info (tree_view, column);
9336
9337   if (tree_view->priv->column_drag_info == NULL)
9338     return;
9339
9340   if (tree_view->priv->drag_window == NULL)
9341     {
9342       GdkWindowAttr attributes;
9343       guint attributes_mask;
9344
9345       gtk_widget_get_allocation (column->button, &button_allocation);
9346
9347       attributes.window_type = GDK_WINDOW_CHILD;
9348       attributes.wclass = GDK_INPUT_OUTPUT;
9349       attributes.x = button_allocation.x;
9350       attributes.y = 0;
9351       attributes.width = button_allocation.width;
9352       attributes.height = button_allocation.height;
9353       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9354       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9355       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9356
9357       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9358                                                      &attributes,
9359                                                      attributes_mask);
9360       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9361     }
9362
9363   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9364   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9365
9366   gtk_grab_remove (column->button);
9367
9368   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9369   send_event->crossing.send_event = TRUE;
9370   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9371   send_event->crossing.subwindow = NULL;
9372   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9373   send_event->crossing.time = GDK_CURRENT_TIME;
9374   gdk_event_set_device (send_event, device);
9375
9376   gtk_propagate_event (column->button, send_event);
9377   gdk_event_free (send_event);
9378
9379   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9380   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9381   send_event->button.send_event = TRUE;
9382   send_event->button.time = GDK_CURRENT_TIME;
9383   send_event->button.x = -1;
9384   send_event->button.y = -1;
9385   send_event->button.axes = NULL;
9386   send_event->button.state = 0;
9387   send_event->button.button = 1;
9388   send_event->button.x_root = 0;
9389   send_event->button.y_root = 0;
9390   gdk_event_set_device (send_event, device);
9391
9392   gtk_propagate_event (column->button, send_event);
9393   gdk_event_free (send_event);
9394
9395   /* Kids, don't try this at home */
9396   g_object_ref (column->button);
9397   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9398   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9399   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9400   g_object_unref (column->button);
9401
9402   gtk_widget_get_allocation (column->button, &button_allocation);
9403   tree_view->priv->drag_column_x = button_allocation.x;
9404   allocation = button_allocation;
9405   allocation.x = 0;
9406   gtk_widget_size_allocate (column->button, &allocation);
9407   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9408
9409   tree_view->priv->drag_column = column;
9410   gdk_window_show (tree_view->priv->drag_window);
9411
9412   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9413   while (gtk_events_pending ())
9414     gtk_main_iteration ();
9415
9416   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9417   gdk_pointer_grab (tree_view->priv->drag_window,
9418                     FALSE,
9419                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9420                     NULL, NULL, GDK_CURRENT_TIME);
9421   gdk_keyboard_grab (tree_view->priv->drag_window,
9422                      FALSE,
9423                      GDK_CURRENT_TIME);
9424 }
9425
9426 static void
9427 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9428                                 GtkRBTree          *tree,
9429                                 GtkRBNode          *node)
9430 {
9431   GtkAllocation allocation;
9432   GdkRectangle rect;
9433
9434   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9435     return;
9436
9437   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9438   rect.x = 0;
9439   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9440
9441   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9442   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9443
9444   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9445 }
9446
9447 void
9448 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9449                                 GtkRBTree          *tree,
9450                                 GtkRBNode          *node,
9451                                 const GdkRectangle *clip_rect)
9452 {
9453   GtkAllocation allocation;
9454   GdkRectangle rect;
9455
9456   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9457     return;
9458
9459   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9460   rect.x = 0;
9461   rect.width = MAX (tree_view->priv->width, allocation.width);
9462
9463   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9464   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9465
9466   if (clip_rect)
9467     {
9468       GdkRectangle new_rect;
9469
9470       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9471
9472       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9473     }
9474   else
9475     {
9476       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9477     }
9478 }
9479
9480 static void
9481 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9482                                GtkTreePath        *path,
9483                                const GdkRectangle *clip_rect)
9484 {
9485   GtkRBTree *tree = NULL;
9486   GtkRBNode *node = NULL;
9487
9488   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9489
9490   if (tree)
9491     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9492 }
9493
9494 /* x and y are the mouse position
9495  */
9496 static void
9497 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9498                           cairo_t     *cr,
9499                           GtkRBTree   *tree,
9500                           GtkRBNode   *node,
9501                           /* in bin_window coordinates */
9502                           gint         x,
9503                           gint         y)
9504 {
9505   GdkRectangle area;
9506   GtkStateType state;
9507   GtkWidget *widget;
9508   gint x_offset = 0;
9509   gint x2;
9510   gint vertical_separator;
9511   gint expander_size;
9512   GtkExpanderStyle expander_style;
9513
9514   widget = GTK_WIDGET (tree_view);
9515
9516   gtk_widget_style_get (widget,
9517                         "vertical-separator", &vertical_separator,
9518                         NULL);
9519   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9520
9521   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9522     return;
9523
9524   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9525
9526   area.x = x_offset;
9527   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9528   area.width = expander_size + 2;
9529   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9530
9531   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9532     {
9533       state = GTK_STATE_INSENSITIVE;
9534     }
9535   else if (node == tree_view->priv->button_pressed_node)
9536     {
9537       if (x >= area.x && x <= (area.x + area.width) &&
9538           y >= area.y && y <= (area.y + area.height))
9539         state = GTK_STATE_ACTIVE;
9540       else
9541         state = GTK_STATE_NORMAL;
9542     }
9543   else
9544     {
9545       if (node == tree_view->priv->prelight_node &&
9546           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9547         state = GTK_STATE_PRELIGHT;
9548       else
9549         state = GTK_STATE_NORMAL;
9550     }
9551
9552   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9553     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9554   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9555     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9556   else if (node->children != NULL)
9557     expander_style = GTK_EXPANDER_EXPANDED;
9558   else
9559     expander_style = GTK_EXPANDER_COLLAPSED;
9560
9561   gtk_paint_expander (gtk_widget_get_style (widget),
9562                       cr,
9563                       state,
9564                       widget,
9565                       "treeview",
9566                       area.x + area.width / 2,
9567                       area.y + area.height / 2,
9568                       expander_style);
9569 }
9570
9571 static void
9572 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9573
9574 {
9575   GtkTreePath *cursor_path;
9576
9577   if ((tree_view->priv->tree == NULL) ||
9578       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9579     return;
9580
9581   cursor_path = NULL;
9582   if (tree_view->priv->cursor)
9583     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9584
9585   if (cursor_path == NULL)
9586     {
9587       /* Consult the selection before defaulting to the
9588        * first focusable element
9589        */
9590       GList *selected_rows;
9591       GtkTreeModel *model;
9592       GtkTreeSelection *selection;
9593
9594       selection = gtk_tree_view_get_selection (tree_view);
9595       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9596
9597       if (selected_rows)
9598         {
9599           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9600           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9601           g_list_free (selected_rows);
9602         }
9603       else
9604         {
9605           cursor_path = gtk_tree_path_new_first ();
9606           search_first_focusable_path (tree_view, &cursor_path,
9607                                        TRUE, NULL, NULL);
9608         }
9609
9610       gtk_tree_row_reference_free (tree_view->priv->cursor);
9611       tree_view->priv->cursor = NULL;
9612
9613       if (cursor_path)
9614         {
9615           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9616             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9617           else
9618             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9619         }
9620     }
9621
9622   if (cursor_path)
9623     {
9624       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9625
9626       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9627       gtk_tree_path_free (cursor_path);
9628
9629       if (tree_view->priv->focus_column == NULL)
9630         {
9631           GList *list;
9632           for (list = tree_view->priv->columns; list; list = list->next)
9633             {
9634               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9635                 {
9636                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9637                   break;
9638                 }
9639             }
9640         }
9641     }
9642 }
9643
9644 static void
9645 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9646                                    gint         count)
9647 {
9648   gint selection_count;
9649   GtkRBTree *cursor_tree = NULL;
9650   GtkRBNode *cursor_node = NULL;
9651   GtkRBTree *new_cursor_tree = NULL;
9652   GtkRBNode *new_cursor_node = NULL;
9653   GtkTreePath *cursor_path = NULL;
9654   gboolean grab_focus = TRUE;
9655   gboolean selectable;
9656
9657   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9658     return;
9659
9660   cursor_path = NULL;
9661   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9662     /* FIXME: we lost the cursor; should we get the first? */
9663     return;
9664
9665   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9666   _gtk_tree_view_find_node (tree_view, cursor_path,
9667                             &cursor_tree, &cursor_node);
9668
9669   if (cursor_tree == NULL)
9670     /* FIXME: we lost the cursor; should we get the first? */
9671     return;
9672
9673   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9674   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9675                                                       cursor_node,
9676                                                       cursor_path);
9677
9678   if (selection_count == 0
9679       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9680       && !tree_view->priv->ctrl_pressed
9681       && selectable)
9682     {
9683       /* Don't move the cursor, but just select the current node */
9684       new_cursor_tree = cursor_tree;
9685       new_cursor_node = cursor_node;
9686     }
9687   else
9688     {
9689       if (count == -1)
9690         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9691                                &new_cursor_tree, &new_cursor_node);
9692       else
9693         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9694                                &new_cursor_tree, &new_cursor_node);
9695     }
9696
9697   gtk_tree_path_free (cursor_path);
9698
9699   if (new_cursor_node)
9700     {
9701       cursor_path = _gtk_tree_view_find_path (tree_view,
9702                                               new_cursor_tree, new_cursor_node);
9703
9704       search_first_focusable_path (tree_view, &cursor_path,
9705                                    (count != -1),
9706                                    &new_cursor_tree,
9707                                    &new_cursor_node);
9708
9709       if (cursor_path)
9710         gtk_tree_path_free (cursor_path);
9711     }
9712
9713   /*
9714    * If the list has only one item and multi-selection is set then select
9715    * the row (if not yet selected).
9716    */
9717   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9718       new_cursor_node == NULL)
9719     {
9720       if (count == -1)
9721         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9722                                &new_cursor_tree, &new_cursor_node);
9723       else
9724         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9725                                &new_cursor_tree, &new_cursor_node);
9726
9727       if (new_cursor_node == NULL
9728           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9729         {
9730           new_cursor_node = cursor_node;
9731           new_cursor_tree = cursor_tree;
9732         }
9733       else
9734         {
9735           new_cursor_node = NULL;
9736         }
9737     }
9738
9739   if (new_cursor_node)
9740     {
9741       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9742       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9743       gtk_tree_path_free (cursor_path);
9744     }
9745   else
9746     {
9747       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9748
9749       if (!tree_view->priv->shift_pressed)
9750         {
9751           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9752                                           count < 0 ?
9753                                           GTK_DIR_UP : GTK_DIR_DOWN))
9754             {
9755               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9756
9757               if (toplevel)
9758                 gtk_widget_child_focus (toplevel,
9759                                         count < 0 ?
9760                                         GTK_DIR_TAB_BACKWARD :
9761                                         GTK_DIR_TAB_FORWARD);
9762
9763               grab_focus = FALSE;
9764             }
9765         }
9766       else
9767         {
9768           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9769         }
9770     }
9771
9772   if (grab_focus)
9773     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9774 }
9775
9776 static void
9777 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9778                                         gint         count)
9779 {
9780   GtkRBTree *cursor_tree = NULL;
9781   GtkRBNode *cursor_node = NULL;
9782   GtkTreePath *old_cursor_path = NULL;
9783   GtkTreePath *cursor_path = NULL;
9784   GtkRBTree *start_cursor_tree = NULL;
9785   GtkRBNode *start_cursor_node = NULL;
9786   gint y;
9787   gint window_y;
9788   gint vertical_separator;
9789
9790   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9791     return;
9792
9793   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9794     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9795   else
9796     /* This is sorta weird.  Focus in should give us a cursor */
9797     return;
9798
9799   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9800   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9801                             &cursor_tree, &cursor_node);
9802
9803   if (cursor_tree == NULL)
9804     {
9805       /* FIXME: we lost the cursor.  Should we try to get one? */
9806       gtk_tree_path_free (old_cursor_path);
9807       return;
9808     }
9809   g_return_if_fail (cursor_node != NULL);
9810
9811   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9812   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9813   y += tree_view->priv->cursor_offset;
9814   y += count * (int)tree_view->priv->vadjustment->page_increment;
9815   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9816
9817   if (y >= tree_view->priv->height)
9818     y = tree_view->priv->height - 1;
9819
9820   tree_view->priv->cursor_offset =
9821     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9822                              &cursor_tree, &cursor_node);
9823
9824   if (cursor_tree == NULL)
9825     {
9826       /* FIXME: we lost the cursor.  Should we try to get one? */
9827       gtk_tree_path_free (old_cursor_path);
9828       return;
9829     }
9830
9831   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9832     {
9833       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9834                              &cursor_tree, &cursor_node);
9835       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9836     }
9837
9838   y -= tree_view->priv->cursor_offset;
9839   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9840
9841   start_cursor_tree = cursor_tree;
9842   start_cursor_node = cursor_node;
9843
9844   if (! search_first_focusable_path (tree_view, &cursor_path,
9845                                      (count != -1),
9846                                      &cursor_tree, &cursor_node))
9847     {
9848       /* It looks like we reached the end of the view without finding
9849        * a focusable row.  We will step backwards to find the last
9850        * focusable row.
9851        */
9852       cursor_tree = start_cursor_tree;
9853       cursor_node = start_cursor_node;
9854       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9855
9856       search_first_focusable_path (tree_view, &cursor_path,
9857                                    (count == -1),
9858                                    &cursor_tree, &cursor_node);
9859     }
9860
9861   if (!cursor_path)
9862     goto cleanup;
9863
9864   /* update y */
9865   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9866
9867   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9868
9869   y -= window_y;
9870   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9871   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9872   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9873
9874   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9875     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9876
9877   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9878
9879 cleanup:
9880   gtk_tree_path_free (old_cursor_path);
9881   gtk_tree_path_free (cursor_path);
9882 }
9883
9884 static void
9885 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9886                                       gint         count)
9887 {
9888   GtkRBTree *cursor_tree = NULL;
9889   GtkRBNode *cursor_node = NULL;
9890   GtkTreePath *cursor_path = NULL;
9891   GtkTreeViewColumn *column;
9892   GtkTreeIter iter;
9893   GList *list;
9894   gboolean found_column = FALSE;
9895   gboolean rtl;
9896
9897   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9898
9899   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9900     return;
9901
9902   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9903     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9904   else
9905     return;
9906
9907   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9908   if (cursor_tree == NULL)
9909     return;
9910   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9911     {
9912       gtk_tree_path_free (cursor_path);
9913       return;
9914     }
9915   gtk_tree_path_free (cursor_path);
9916
9917   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9918   if (tree_view->priv->focus_column)
9919     {
9920       for (; list; list = (rtl ? list->prev : list->next))
9921         {
9922           if (list->data == tree_view->priv->focus_column)
9923             break;
9924         }
9925     }
9926
9927   while (list)
9928     {
9929       gboolean left, right;
9930
9931       column = list->data;
9932       if (column->visible == FALSE)
9933         goto loop_end;
9934
9935       gtk_tree_view_column_cell_set_cell_data (column,
9936                                                tree_view->priv->model,
9937                                                &iter,
9938                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9939                                                cursor_node->children?TRUE:FALSE);
9940
9941       if (rtl)
9942         {
9943           right = list->prev ? TRUE : FALSE;
9944           left = list->next ? TRUE : FALSE;
9945         }
9946       else
9947         {
9948           left = list->prev ? TRUE : FALSE;
9949           right = list->next ? TRUE : FALSE;
9950         }
9951
9952       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9953         {
9954           tree_view->priv->focus_column = column;
9955           found_column = TRUE;
9956           break;
9957         }
9958     loop_end:
9959       if (count == 1)
9960         list = rtl ? list->prev : list->next;
9961       else
9962         list = rtl ? list->next : list->prev;
9963     }
9964
9965   if (found_column)
9966     {
9967       if (!gtk_tree_view_has_special_cell (tree_view))
9968         _gtk_tree_view_queue_draw_node (tree_view,
9969                                         cursor_tree,
9970                                         cursor_node,
9971                                         NULL);
9972       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9973       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9974     }
9975   else
9976     {
9977       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9978     }
9979
9980   gtk_tree_view_clamp_column_visible (tree_view,
9981                                       tree_view->priv->focus_column, TRUE);
9982 }
9983
9984 static void
9985 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9986                                      gint         count)
9987 {
9988   GtkRBTree *cursor_tree;
9989   GtkRBNode *cursor_node;
9990   GtkTreePath *path;
9991   GtkTreePath *old_path;
9992
9993   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9994     return;
9995
9996   g_return_if_fail (tree_view->priv->tree != NULL);
9997
9998   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9999
10000   cursor_tree = tree_view->priv->tree;
10001   cursor_node = cursor_tree->root;
10002
10003   if (count == -1)
10004     {
10005       while (cursor_node && cursor_node->left != cursor_tree->nil)
10006         cursor_node = cursor_node->left;
10007
10008       /* Now go forward to find the first focusable row. */
10009       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10010       search_first_focusable_path (tree_view, &path,
10011                                    TRUE, &cursor_tree, &cursor_node);
10012     }
10013   else
10014     {
10015       do
10016         {
10017           while (cursor_node && cursor_node->right != cursor_tree->nil)
10018             cursor_node = cursor_node->right;
10019           if (cursor_node->children == NULL)
10020             break;
10021
10022           cursor_tree = cursor_node->children;
10023           cursor_node = cursor_tree->root;
10024         }
10025       while (1);
10026
10027       /* Now go backwards to find last focusable row. */
10028       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10029       search_first_focusable_path (tree_view, &path,
10030                                    FALSE, &cursor_tree, &cursor_node);
10031     }
10032
10033   if (!path)
10034     goto cleanup;
10035
10036   if (gtk_tree_path_compare (old_path, path))
10037     {
10038       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10039       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10040     }
10041   else
10042     {
10043       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10044     }
10045
10046 cleanup:
10047   gtk_tree_path_free (old_path);
10048   gtk_tree_path_free (path);
10049 }
10050
10051 static gboolean
10052 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10053 {
10054   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10055     return FALSE;
10056
10057   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10058     return FALSE;
10059
10060   gtk_tree_selection_select_all (tree_view->priv->selection);
10061
10062   return TRUE;
10063 }
10064
10065 static gboolean
10066 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10067 {
10068   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10069     return FALSE;
10070
10071   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10072     return FALSE;
10073
10074   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10075
10076   return TRUE;
10077 }
10078
10079 static gboolean
10080 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10081                                       gboolean     start_editing)
10082 {
10083   GtkRBTree *new_tree = NULL;
10084   GtkRBNode *new_node = NULL;
10085   GtkRBTree *cursor_tree = NULL;
10086   GtkRBNode *cursor_node = NULL;
10087   GtkTreePath *cursor_path = NULL;
10088   GtkTreeSelectMode mode = 0;
10089
10090   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10091     return FALSE;
10092
10093   if (tree_view->priv->cursor)
10094     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10095
10096   if (cursor_path == NULL)
10097     return FALSE;
10098
10099   _gtk_tree_view_find_node (tree_view, cursor_path,
10100                             &cursor_tree, &cursor_node);
10101
10102   if (cursor_tree == NULL)
10103     {
10104       gtk_tree_path_free (cursor_path);
10105       return FALSE;
10106     }
10107
10108   if (!tree_view->priv->shift_pressed && start_editing &&
10109       tree_view->priv->focus_column)
10110     {
10111       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10112         {
10113           gtk_tree_path_free (cursor_path);
10114           return TRUE;
10115         }
10116     }
10117
10118   if (tree_view->priv->ctrl_pressed)
10119     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10120   if (tree_view->priv->shift_pressed)
10121     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10122
10123   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10124                                             cursor_node,
10125                                             cursor_tree,
10126                                             cursor_path,
10127                                             mode,
10128                                             FALSE);
10129
10130   /* We bail out if the original (tree, node) don't exist anymore after
10131    * handling the selection-changed callback.  We do return TRUE because
10132    * the key press has been handled at this point.
10133    */
10134   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10135
10136   if (cursor_tree != new_tree || cursor_node != new_node)
10137     return FALSE;
10138
10139   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10140
10141   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10142   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10143
10144   if (!tree_view->priv->shift_pressed)
10145     gtk_tree_view_row_activated (tree_view, cursor_path,
10146                                  tree_view->priv->focus_column);
10147     
10148   gtk_tree_path_free (cursor_path);
10149
10150   return TRUE;
10151 }
10152
10153 static gboolean
10154 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10155 {
10156   GtkRBTree *new_tree = NULL;
10157   GtkRBNode *new_node = NULL;
10158   GtkRBTree *cursor_tree = NULL;
10159   GtkRBNode *cursor_node = NULL;
10160   GtkTreePath *cursor_path = NULL;
10161
10162   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10163     return FALSE;
10164
10165   cursor_path = NULL;
10166   if (tree_view->priv->cursor)
10167     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10168
10169   if (cursor_path == NULL)
10170     return FALSE;
10171
10172   _gtk_tree_view_find_node (tree_view, cursor_path,
10173                             &cursor_tree, &cursor_node);
10174   if (cursor_tree == NULL)
10175     {
10176       gtk_tree_path_free (cursor_path);
10177       return FALSE;
10178     }
10179
10180   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10181                                             cursor_node,
10182                                             cursor_tree,
10183                                             cursor_path,
10184                                             GTK_TREE_SELECT_MODE_TOGGLE,
10185                                             FALSE);
10186
10187   /* We bail out if the original (tree, node) don't exist anymore after
10188    * handling the selection-changed callback.  We do return TRUE because
10189    * the key press has been handled at this point.
10190    */
10191   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10192
10193   if (cursor_tree != new_tree || cursor_node != new_node)
10194     return FALSE;
10195
10196   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10197
10198   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10199   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10200   gtk_tree_path_free (cursor_path);
10201
10202   return TRUE;
10203 }
10204
10205 static gboolean
10206 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10207                                                gboolean     logical,
10208                                                gboolean     expand,
10209                                                gboolean     open_all)
10210 {
10211   GtkTreePath *cursor_path = NULL;
10212   GtkRBTree *tree;
10213   GtkRBNode *node;
10214
10215   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10216     return FALSE;
10217
10218   cursor_path = NULL;
10219   if (tree_view->priv->cursor)
10220     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10221
10222   if (cursor_path == NULL)
10223     return FALSE;
10224
10225   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10226     return FALSE;
10227
10228   /* Don't handle the event if we aren't an expander */
10229   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10230     return FALSE;
10231
10232   if (!logical
10233       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10234     expand = !expand;
10235
10236   if (expand)
10237     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10238   else
10239     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10240
10241   gtk_tree_path_free (cursor_path);
10242
10243   return TRUE;
10244 }
10245
10246 static gboolean
10247 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10248 {
10249   GtkRBTree *cursor_tree = NULL;
10250   GtkRBNode *cursor_node = NULL;
10251   GtkTreePath *cursor_path = NULL;
10252   GdkModifierType state;
10253
10254   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10255     goto out;
10256
10257   cursor_path = NULL;
10258   if (tree_view->priv->cursor)
10259     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10260
10261   if (cursor_path == NULL)
10262     goto out;
10263
10264   _gtk_tree_view_find_node (tree_view, cursor_path,
10265                             &cursor_tree, &cursor_node);
10266   if (cursor_tree == NULL)
10267     {
10268       gtk_tree_path_free (cursor_path);
10269       goto out;
10270     }
10271
10272   if (cursor_tree->parent_node)
10273     {
10274       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10275       cursor_node = cursor_tree->parent_node;
10276       cursor_tree = cursor_tree->parent_tree;
10277
10278       gtk_tree_path_up (cursor_path);
10279
10280       if (gtk_get_current_event_state (&state))
10281         {
10282           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10283             tree_view->priv->ctrl_pressed = TRUE;
10284         }
10285
10286       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10287       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10288
10289       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10290       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10291       gtk_tree_path_free (cursor_path);
10292
10293       tree_view->priv->ctrl_pressed = FALSE;
10294
10295       return TRUE;
10296     }
10297
10298  out:
10299
10300   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10301   return FALSE;
10302 }
10303
10304 static gboolean
10305 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10306 {
10307   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10308   tree_view->priv->typeselect_flush_timeout = 0;
10309
10310   return FALSE;
10311 }
10312
10313 /* Cut and paste from gtkwindow.c */
10314 static void
10315 send_focus_change (GtkWidget *widget,
10316                    GdkDevice *device,
10317                    gboolean   in)
10318 {
10319   GdkDeviceManager *device_manager;
10320   GList *devices, *d;
10321
10322   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10323   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10324   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10325   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10326
10327   for (d = devices; d; d = d->next)
10328     {
10329       GdkDevice *dev = d->data;
10330       GdkEvent *fevent;
10331       GdkWindow *window;
10332
10333       if (dev->source != GDK_SOURCE_KEYBOARD)
10334         continue;
10335
10336       window = gtk_widget_get_window (widget);
10337
10338       /* Skip non-master keyboards that haven't
10339        * selected for events from this window
10340        */
10341       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10342           !gdk_window_get_device_events (window, dev))
10343         continue;
10344
10345       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10346
10347       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10348       fevent->focus_change.window = g_object_ref (window);
10349       fevent->focus_change.in = in;
10350       gdk_event_set_device (fevent, device);
10351
10352       gtk_widget_send_focus_change (widget, fevent);
10353
10354       gdk_event_free (fevent);
10355     }
10356 }
10357
10358 static void
10359 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10360 {
10361   GtkWidget *frame, *vbox, *toplevel;
10362   GdkScreen *screen;
10363
10364   if (tree_view->priv->search_custom_entry_set)
10365     return;
10366
10367   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10368   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10369
10370    if (tree_view->priv->search_window != NULL)
10371      {
10372        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10373          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10374                                       GTK_WINDOW (tree_view->priv->search_window));
10375        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10376          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10377                                          GTK_WINDOW (tree_view->priv->search_window));
10378
10379        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10380
10381        return;
10382      }
10383    
10384   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10385   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10386
10387   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10388     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10389                                  GTK_WINDOW (tree_view->priv->search_window));
10390
10391   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10392                             GDK_WINDOW_TYPE_HINT_UTILITY);
10393   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10394   g_signal_connect (tree_view->priv->search_window, "delete-event",
10395                     G_CALLBACK (gtk_tree_view_search_delete_event),
10396                     tree_view);
10397   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10398                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10399                     tree_view);
10400   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10401                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10402                     tree_view);
10403   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10404                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10405                     tree_view);
10406
10407   frame = gtk_frame_new (NULL);
10408   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10409   gtk_widget_show (frame);
10410   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10411
10412   vbox = gtk_vbox_new (FALSE, 0);
10413   gtk_widget_show (vbox);
10414   gtk_container_add (GTK_CONTAINER (frame), vbox);
10415   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10416
10417   /* add entry */
10418   tree_view->priv->search_entry = gtk_entry_new ();
10419   gtk_widget_show (tree_view->priv->search_entry);
10420   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10421                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10422                     tree_view);
10423   g_signal_connect (tree_view->priv->search_entry,
10424                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10425                     tree_view);
10426   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10427                     "preedit-changed",
10428                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10429                     tree_view);
10430   gtk_container_add (GTK_CONTAINER (vbox),
10431                      tree_view->priv->search_entry);
10432
10433   gtk_widget_realize (tree_view->priv->search_entry);
10434 }
10435
10436 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10437  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10438  */
10439 static gboolean
10440 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10441                                              GdkDevice   *device,
10442                                              gboolean     keybinding)
10443 {
10444   /* We only start interactive search if we have focus or the columns
10445    * have focus.  If one of our children have focus, we don't want to
10446    * start the search.
10447    */
10448   GList *list;
10449   gboolean found_focus = FALSE;
10450   GtkWidgetClass *entry_parent_class;
10451   
10452   if (!tree_view->priv->enable_search && !keybinding)
10453     return FALSE;
10454
10455   if (tree_view->priv->search_custom_entry_set)
10456     return FALSE;
10457
10458   if (tree_view->priv->search_window != NULL &&
10459       gtk_widget_get_visible (tree_view->priv->search_window))
10460     return TRUE;
10461
10462   for (list = tree_view->priv->columns; list; list = list->next)
10463     {
10464       GtkTreeViewColumn *column;
10465
10466       column = list->data;
10467       if (! column->visible)
10468         continue;
10469
10470       if (gtk_widget_has_focus (column->button))
10471         {
10472           found_focus = TRUE;
10473           break;
10474         }
10475     }
10476   
10477   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10478     found_focus = TRUE;
10479
10480   if (!found_focus)
10481     return FALSE;
10482
10483   if (tree_view->priv->search_column < 0)
10484     return FALSE;
10485
10486   gtk_tree_view_ensure_interactive_directory (tree_view);
10487
10488   if (keybinding)
10489     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10490
10491   /* done, show it */
10492   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10493   gtk_widget_show (tree_view->priv->search_window);
10494   if (tree_view->priv->search_entry_changed_id == 0)
10495     {
10496       tree_view->priv->search_entry_changed_id =
10497         g_signal_connect (tree_view->priv->search_entry, "changed",
10498                           G_CALLBACK (gtk_tree_view_search_init),
10499                           tree_view);
10500     }
10501
10502   tree_view->priv->typeselect_flush_timeout =
10503     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10504                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10505                    tree_view);
10506
10507   /* Grab focus will select all the text.  We don't want that to happen, so we
10508    * call the parent instance and bypass the selection change.  This is probably
10509    * really non-kosher. */
10510   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10511   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10512
10513   /* send focus-in event */
10514   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10515
10516   /* search first matching iter */
10517   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10518
10519   return TRUE;
10520 }
10521
10522 static gboolean
10523 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10524 {
10525   return gtk_tree_view_real_start_interactive_search (tree_view,
10526                                                       gtk_get_current_event_device (),
10527                                                       TRUE);
10528 }
10529
10530 /* this function returns the new width of the column being resized given
10531  * the column and x position of the cursor; the x cursor position is passed
10532  * in as a pointer and automagicly corrected if it's beyond min/max limits
10533  */
10534 static gint
10535 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10536                                 gint       i,
10537                                 gint      *x)
10538 {
10539   GtkAllocation allocation;
10540   GtkTreeViewColumn *column;
10541   GtkRequisition button_req;
10542   gint width;
10543   gboolean rtl;
10544
10545   /* first translate the x position from widget->window
10546    * to clist->clist_window
10547    */
10548   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10549   column = g_list_nth (tree_view->priv->columns, i)->data;
10550   gtk_widget_get_allocation (column->button, &allocation);
10551   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10552
10553   /* Clamp down the value */
10554   if (column->min_width == -1)
10555     {
10556       gtk_widget_get_preferred_size (column->button, &button_req, NULL);
10557       width = MAX (button_req.width, width);
10558     }
10559   else
10560     width = MAX (column->min_width,
10561                  width);
10562   if (column->max_width != -1)
10563     width = MIN (width, column->max_width);
10564
10565   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10566
10567   return width;
10568 }
10569
10570
10571 /* FIXME this adjust_allocation is a big cut-and-paste from
10572  * GtkCList, needs to be some "official" way to do this
10573  * factored out.
10574  */
10575 typedef struct
10576 {
10577   GdkWindow *window;
10578   int dx;
10579   int dy;
10580 } ScrollData;
10581
10582 /* The window to which widget->window is relative */
10583 #define ALLOCATION_WINDOW(widget)               \
10584    (!gtk_widget_get_has_window (widget) ?                   \
10585     gtk_widget_get_window (widget) :                        \
10586     gdk_window_get_parent (gtk_widget_get_window (widget)))
10587
10588 static void
10589 adjust_allocation_recurse (GtkWidget *widget,
10590                            gpointer   data)
10591 {
10592   GtkAllocation allocation;
10593   ScrollData *scroll_data = data;
10594
10595   /* Need to really size allocate instead of just poking
10596    * into widget->allocation if the widget is not realized.
10597    * FIXME someone figure out why this was.
10598    */
10599   gtk_widget_get_allocation (widget, &allocation);
10600   if (!gtk_widget_get_realized (widget))
10601     {
10602       if (gtk_widget_get_visible (widget))
10603         {
10604           GdkRectangle tmp_rectangle = allocation;
10605           tmp_rectangle.x += scroll_data->dx;
10606           tmp_rectangle.y += scroll_data->dy;
10607           
10608           gtk_widget_size_allocate (widget, &tmp_rectangle);
10609         }
10610     }
10611   else
10612     {
10613       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10614         {
10615           allocation.x += scroll_data->dx;
10616           allocation.y += scroll_data->dy;
10617           gtk_widget_set_allocation (widget, &allocation);
10618
10619           if (GTK_IS_CONTAINER (widget))
10620             gtk_container_forall (GTK_CONTAINER (widget),
10621                                   adjust_allocation_recurse,
10622                                   data);
10623         }
10624     }
10625 }
10626
10627 static void
10628 adjust_allocation (GtkWidget *widget,
10629                    int        dx,
10630                    int        dy)
10631 {
10632   ScrollData scroll_data;
10633
10634   if (gtk_widget_get_realized (widget))
10635     scroll_data.window = ALLOCATION_WINDOW (widget);
10636   else
10637     scroll_data.window = NULL;
10638     
10639   scroll_data.dx = dx;
10640   scroll_data.dy = dy;
10641   
10642   adjust_allocation_recurse (widget, &scroll_data);
10643 }
10644
10645 /* Callbacks */
10646 static void
10647 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10648                                   GtkTreeView   *tree_view)
10649 {
10650   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10651     {
10652       gint dy;
10653         
10654       gdk_window_move (tree_view->priv->bin_window,
10655                        - tree_view->priv->hadjustment->value,
10656                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10657       gdk_window_move (tree_view->priv->header_window,
10658                        - tree_view->priv->hadjustment->value,
10659                        0);
10660       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10661       if (dy)
10662         {
10663           update_prelight (tree_view,
10664                            tree_view->priv->event_last_x,
10665                            tree_view->priv->event_last_y - dy);
10666
10667           if (tree_view->priv->edited_column &&
10668               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10669             {
10670               GList *list;
10671               GtkWidget *widget;
10672               GtkTreeViewChild *child = NULL;
10673
10674               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10675               adjust_allocation (widget, 0, dy); 
10676               
10677               for (list = tree_view->priv->children; list; list = list->next)
10678                 {
10679                   child = (GtkTreeViewChild *)list->data;
10680                   if (child->widget == widget)
10681                     {
10682                       child->y += dy;
10683                       break;
10684                     }
10685                 }
10686             }
10687         }
10688       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10689
10690       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10691         {
10692           /* update our dy and top_row */
10693           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10694
10695           if (!tree_view->priv->in_top_row_to_dy)
10696             gtk_tree_view_dy_to_top_row (tree_view);
10697         }
10698
10699       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10700       gtk_tree_view_bin_process_updates (tree_view);
10701     }
10702 }
10703
10704 \f
10705
10706 /* Public methods
10707  */
10708
10709 /**
10710  * gtk_tree_view_new:
10711  *
10712  * Creates a new #GtkTreeView widget.
10713  *
10714  * Return value: A newly created #GtkTreeView widget.
10715  **/
10716 GtkWidget *
10717 gtk_tree_view_new (void)
10718 {
10719   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10720 }
10721
10722 /**
10723  * gtk_tree_view_new_with_model:
10724  * @model: the model.
10725  *
10726  * Creates a new #GtkTreeView widget with the model initialized to @model.
10727  *
10728  * Return value: A newly created #GtkTreeView widget.
10729  **/
10730 GtkWidget *
10731 gtk_tree_view_new_with_model (GtkTreeModel *model)
10732 {
10733   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10734 }
10735
10736 /* Public Accessors
10737  */
10738
10739 /**
10740  * gtk_tree_view_get_model:
10741  * @tree_view: a #GtkTreeView
10742  *
10743  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10744  * model is unset.
10745  *
10746  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10747  **/
10748 GtkTreeModel *
10749 gtk_tree_view_get_model (GtkTreeView *tree_view)
10750 {
10751   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10752
10753   return tree_view->priv->model;
10754 }
10755
10756 /**
10757  * gtk_tree_view_set_model:
10758  * @tree_view: A #GtkTreeNode.
10759  * @model: (allow-none): The model.
10760  *
10761  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10762  * set, it will remove it before setting the new model.  If @model is %NULL,
10763  * then it will unset the old model.
10764  **/
10765 void
10766 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10767                          GtkTreeModel *model)
10768 {
10769   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10770   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10771
10772   if (model == tree_view->priv->model)
10773     return;
10774
10775   if (tree_view->priv->scroll_to_path)
10776     {
10777       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10778       tree_view->priv->scroll_to_path = NULL;
10779     }
10780
10781   if (tree_view->priv->model)
10782     {
10783       GList *tmplist = tree_view->priv->columns;
10784
10785       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10786       gtk_tree_view_stop_editing (tree_view, TRUE);
10787
10788       remove_expand_collapse_timeout (tree_view);
10789
10790       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10791                                             gtk_tree_view_row_changed,
10792                                             tree_view);
10793       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10794                                             gtk_tree_view_row_inserted,
10795                                             tree_view);
10796       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10797                                             gtk_tree_view_row_has_child_toggled,
10798                                             tree_view);
10799       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10800                                             gtk_tree_view_row_deleted,
10801                                             tree_view);
10802       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10803                                             gtk_tree_view_rows_reordered,
10804                                             tree_view);
10805
10806       for (; tmplist; tmplist = tmplist->next)
10807         _gtk_tree_view_column_unset_model (tmplist->data,
10808                                            tree_view->priv->model);
10809
10810       if (tree_view->priv->tree)
10811         gtk_tree_view_free_rbtree (tree_view);
10812
10813       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10814       tree_view->priv->drag_dest_row = NULL;
10815       gtk_tree_row_reference_free (tree_view->priv->cursor);
10816       tree_view->priv->cursor = NULL;
10817       gtk_tree_row_reference_free (tree_view->priv->anchor);
10818       tree_view->priv->anchor = NULL;
10819       gtk_tree_row_reference_free (tree_view->priv->top_row);
10820       tree_view->priv->top_row = NULL;
10821       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10822       tree_view->priv->scroll_to_path = NULL;
10823
10824       tree_view->priv->scroll_to_column = NULL;
10825
10826       g_object_unref (tree_view->priv->model);
10827
10828       tree_view->priv->search_column = -1;
10829       tree_view->priv->fixed_height_check = 0;
10830       tree_view->priv->fixed_height = -1;
10831       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10832       tree_view->priv->last_button_x = -1;
10833       tree_view->priv->last_button_y = -1;
10834     }
10835
10836   tree_view->priv->model = model;
10837
10838   if (tree_view->priv->model)
10839     {
10840       gint i;
10841       GtkTreePath *path;
10842       GtkTreeIter iter;
10843       GtkTreeModelFlags flags;
10844
10845       if (tree_view->priv->search_column == -1)
10846         {
10847           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10848             {
10849               GType type = gtk_tree_model_get_column_type (model, i);
10850
10851               if (g_value_type_transformable (type, G_TYPE_STRING))
10852                 {
10853                   tree_view->priv->search_column = i;
10854                   break;
10855                 }
10856             }
10857         }
10858
10859       g_object_ref (tree_view->priv->model);
10860       g_signal_connect (tree_view->priv->model,
10861                         "row-changed",
10862                         G_CALLBACK (gtk_tree_view_row_changed),
10863                         tree_view);
10864       g_signal_connect (tree_view->priv->model,
10865                         "row-inserted",
10866                         G_CALLBACK (gtk_tree_view_row_inserted),
10867                         tree_view);
10868       g_signal_connect (tree_view->priv->model,
10869                         "row-has-child-toggled",
10870                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10871                         tree_view);
10872       g_signal_connect (tree_view->priv->model,
10873                         "row-deleted",
10874                         G_CALLBACK (gtk_tree_view_row_deleted),
10875                         tree_view);
10876       g_signal_connect (tree_view->priv->model,
10877                         "rows-reordered",
10878                         G_CALLBACK (gtk_tree_view_rows_reordered),
10879                         tree_view);
10880
10881       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10882       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10883         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10884       else
10885         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10886
10887       path = gtk_tree_path_new_first ();
10888       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10889         {
10890           tree_view->priv->tree = _gtk_rbtree_new ();
10891           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10892         }
10893       gtk_tree_path_free (path);
10894
10895       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10896       install_presize_handler (tree_view);
10897     }
10898
10899   g_object_notify (G_OBJECT (tree_view), "model");
10900
10901   if (tree_view->priv->selection)
10902   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10903
10904   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10905     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10906 }
10907
10908 /**
10909  * gtk_tree_view_get_selection:
10910  * @tree_view: A #GtkTreeView.
10911  *
10912  * Gets the #GtkTreeSelection associated with @tree_view.
10913  *
10914  * Return value: (transfer none): A #GtkTreeSelection object.
10915  **/
10916 GtkTreeSelection *
10917 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10918 {
10919   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10920
10921   return tree_view->priv->selection;
10922 }
10923
10924 /**
10925  * gtk_tree_view_get_hadjustment:
10926  * @tree_view: A #GtkTreeView
10927  *
10928  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10929  *
10930  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10931  *     if none is currently being used.
10932  **/
10933 GtkAdjustment *
10934 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10935 {
10936   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10937
10938   if (tree_view->priv->hadjustment == NULL)
10939     gtk_tree_view_set_hadjustment (tree_view, NULL);
10940
10941   return tree_view->priv->hadjustment;
10942 }
10943
10944 /**
10945  * gtk_tree_view_set_hadjustment:
10946  * @tree_view: A #GtkTreeView
10947  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10948  *
10949  * Sets the #GtkAdjustment for the current horizontal aspect.
10950  **/
10951 void
10952 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10953                                GtkAdjustment *adjustment)
10954 {
10955   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10956
10957   gtk_tree_view_set_adjustments (tree_view,
10958                                  adjustment,
10959                                  tree_view->priv->vadjustment);
10960
10961   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10962 }
10963
10964 /**
10965  * gtk_tree_view_get_vadjustment:
10966  * @tree_view: A #GtkTreeView
10967  *
10968  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10969  *
10970  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10971  *     if none is currently being used.
10972  **/
10973 GtkAdjustment *
10974 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10975 {
10976   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10977
10978   if (tree_view->priv->vadjustment == NULL)
10979     gtk_tree_view_set_vadjustment (tree_view, NULL);
10980
10981   return tree_view->priv->vadjustment;
10982 }
10983
10984 /**
10985  * gtk_tree_view_set_vadjustment:
10986  * @tree_view: A #GtkTreeView
10987  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10988  *
10989  * Sets the #GtkAdjustment for the current vertical aspect.
10990  **/
10991 void
10992 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10993                                GtkAdjustment *adjustment)
10994 {
10995   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10996
10997   gtk_tree_view_set_adjustments (tree_view,
10998                                  tree_view->priv->hadjustment,
10999                                  adjustment);
11000
11001   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11002 }
11003
11004 /* Column and header operations */
11005
11006 /**
11007  * gtk_tree_view_get_headers_visible:
11008  * @tree_view: A #GtkTreeView.
11009  *
11010  * Returns %TRUE if the headers on the @tree_view are visible.
11011  *
11012  * Return value: Whether the headers are visible or not.
11013  **/
11014 gboolean
11015 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11016 {
11017   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11018
11019   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11020 }
11021
11022 /**
11023  * gtk_tree_view_set_headers_visible:
11024  * @tree_view: A #GtkTreeView.
11025  * @headers_visible: %TRUE if the headers are visible
11026  *
11027  * Sets the visibility state of the headers.
11028  **/
11029 void
11030 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11031                                    gboolean     headers_visible)
11032 {
11033   gint x, y;
11034   GList *list;
11035   GtkTreeViewColumn *column;
11036   GtkAllocation allocation;
11037
11038   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11039
11040   headers_visible = !! headers_visible;
11041
11042   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11043     return;
11044
11045   if (headers_visible)
11046     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11047   else
11048     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11049
11050   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11051     {
11052       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11053       if (headers_visible)
11054         {
11055           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11056           gdk_window_move_resize (tree_view->priv->bin_window,
11057                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11058                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11059
11060           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11061             gtk_tree_view_map_buttons (tree_view);
11062         }
11063       else
11064         {
11065           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11066
11067           for (list = tree_view->priv->columns; list; list = list->next)
11068             {
11069               column = list->data;
11070               gtk_widget_unmap (column->button);
11071             }
11072           gdk_window_hide (tree_view->priv->header_window);
11073         }
11074     }
11075
11076   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11077   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11078   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11079   tree_view->priv->vadjustment->lower = 0;
11080   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11081   gtk_adjustment_changed (tree_view->priv->vadjustment);
11082
11083   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11084
11085   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11086 }
11087
11088 /**
11089  * gtk_tree_view_columns_autosize:
11090  * @tree_view: A #GtkTreeView.
11091  *
11092  * Resizes all columns to their optimal width. Only works after the
11093  * treeview has been realized.
11094  **/
11095 void
11096 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11097 {
11098   gboolean dirty = FALSE;
11099   GList *list;
11100   GtkTreeViewColumn *column;
11101
11102   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11103
11104   for (list = tree_view->priv->columns; list; list = list->next)
11105     {
11106       column = list->data;
11107       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11108         continue;
11109       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11110       dirty = TRUE;
11111     }
11112
11113   if (dirty)
11114     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11115 }
11116
11117 /**
11118  * gtk_tree_view_set_headers_clickable:
11119  * @tree_view: A #GtkTreeView.
11120  * @setting: %TRUE if the columns are clickable.
11121  *
11122  * Allow the column title buttons to be clicked.
11123  **/
11124 void
11125 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11126                                      gboolean   setting)
11127 {
11128   GList *list;
11129
11130   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11131
11132   for (list = tree_view->priv->columns; list; list = list->next)
11133     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11134
11135   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11136 }
11137
11138
11139 /**
11140  * gtk_tree_view_get_headers_clickable:
11141  * @tree_view: A #GtkTreeView.
11142  *
11143  * Returns whether all header columns are clickable.
11144  *
11145  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11146  *
11147  * Since: 2.10
11148  **/
11149 gboolean 
11150 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11151 {
11152   GList *list;
11153   
11154   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11155
11156   for (list = tree_view->priv->columns; list; list = list->next)
11157     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11158       return FALSE;
11159
11160   return TRUE;
11161 }
11162
11163 /**
11164  * gtk_tree_view_set_rules_hint
11165  * @tree_view: a #GtkTreeView
11166  * @setting: %TRUE if the tree requires reading across rows
11167  *
11168  * This function tells GTK+ that the user interface for your
11169  * application requires users to read across tree rows and associate
11170  * cells with one another. By default, GTK+ will then render the tree
11171  * with alternating row colors. Do <emphasis>not</emphasis> use it
11172  * just because you prefer the appearance of the ruled tree; that's a
11173  * question for the theme. Some themes will draw tree rows in
11174  * alternating colors even when rules are turned off, and users who
11175  * prefer that appearance all the time can choose those themes. You
11176  * should call this function only as a <emphasis>semantic</emphasis>
11177  * hint to the theme engine that your tree makes alternating colors
11178  * useful from a functional standpoint (since it has lots of columns,
11179  * generally).
11180  *
11181  **/
11182 void
11183 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11184                               gboolean      setting)
11185 {
11186   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11187
11188   setting = setting != FALSE;
11189
11190   if (tree_view->priv->has_rules != setting)
11191     {
11192       tree_view->priv->has_rules = setting;
11193       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11194     }
11195
11196   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11197 }
11198
11199 /**
11200  * gtk_tree_view_get_rules_hint
11201  * @tree_view: a #GtkTreeView
11202  *
11203  * Gets the setting set by gtk_tree_view_set_rules_hint().
11204  *
11205  * Return value: %TRUE if rules are useful for the user of this tree
11206  **/
11207 gboolean
11208 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11209 {
11210   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11211
11212   return tree_view->priv->has_rules;
11213 }
11214
11215 /* Public Column functions
11216  */
11217
11218 /**
11219  * gtk_tree_view_append_column:
11220  * @tree_view: A #GtkTreeView.
11221  * @column: The #GtkTreeViewColumn to add.
11222  *
11223  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11224  * mode enabled, then @column must have its "sizing" property set to be
11225  * GTK_TREE_VIEW_COLUMN_FIXED.
11226  *
11227  * Return value: The number of columns in @tree_view after appending.
11228  **/
11229 gint
11230 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11231                              GtkTreeViewColumn *column)
11232 {
11233   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11234   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11235   g_return_val_if_fail (column->tree_view == NULL, -1);
11236
11237   return gtk_tree_view_insert_column (tree_view, column, -1);
11238 }
11239
11240
11241 /**
11242  * gtk_tree_view_remove_column:
11243  * @tree_view: A #GtkTreeView.
11244  * @column: The #GtkTreeViewColumn to remove.
11245  *
11246  * Removes @column from @tree_view.
11247  *
11248  * Return value: The number of columns in @tree_view after removing.
11249  **/
11250 gint
11251 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11252                              GtkTreeViewColumn *column)
11253 {
11254   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11255   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11256   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11257
11258   if (tree_view->priv->focus_column == column)
11259     tree_view->priv->focus_column = NULL;
11260
11261   if (tree_view->priv->edited_column == column)
11262     {
11263       gtk_tree_view_stop_editing (tree_view, TRUE);
11264
11265       /* no need to, but just to be sure ... */
11266       tree_view->priv->edited_column = NULL;
11267     }
11268
11269   if (tree_view->priv->expander_column == column)
11270     tree_view->priv->expander_column = NULL;
11271
11272   g_signal_handlers_disconnect_by_func (column,
11273                                         G_CALLBACK (column_sizing_notify),
11274                                         tree_view);
11275
11276   _gtk_tree_view_column_unset_tree_view (column);
11277
11278   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11279   tree_view->priv->n_columns--;
11280
11281   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11282     {
11283       GList *list;
11284
11285       _gtk_tree_view_column_unrealize_button (column);
11286       for (list = tree_view->priv->columns; list; list = list->next)
11287         {
11288           GtkTreeViewColumn *tmp_column;
11289
11290           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11291           if (tmp_column->visible)
11292             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11293         }
11294
11295       if (tree_view->priv->n_columns == 0 &&
11296           gtk_tree_view_get_headers_visible (tree_view))
11297         gdk_window_hide (tree_view->priv->header_window);
11298
11299       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11300     }
11301
11302   g_object_unref (column);
11303   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11304
11305   return tree_view->priv->n_columns;
11306 }
11307
11308 /**
11309  * gtk_tree_view_insert_column:
11310  * @tree_view: A #GtkTreeView.
11311  * @column: The #GtkTreeViewColumn to be inserted.
11312  * @position: The position to insert @column in.
11313  *
11314  * This inserts the @column into the @tree_view at @position.  If @position is
11315  * -1, then the column is inserted at the end. If @tree_view has
11316  * "fixed_height" mode enabled, then @column must have its "sizing" property
11317  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11318  *
11319  * Return value: The number of columns in @tree_view after insertion.
11320  **/
11321 gint
11322 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11323                              GtkTreeViewColumn *column,
11324                              gint               position)
11325 {
11326   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11327   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11328   g_return_val_if_fail (column->tree_view == NULL, -1);
11329
11330   if (tree_view->priv->fixed_height_mode)
11331     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11332                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11333
11334   g_object_ref_sink (column);
11335
11336   if (tree_view->priv->n_columns == 0 &&
11337       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11338       gtk_tree_view_get_headers_visible (tree_view))
11339     {
11340       gdk_window_show (tree_view->priv->header_window);
11341     }
11342
11343   g_signal_connect (column, "notify::sizing",
11344                     G_CALLBACK (column_sizing_notify), tree_view);
11345
11346   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11347                                             column, position);
11348   tree_view->priv->n_columns++;
11349
11350   _gtk_tree_view_column_set_tree_view (column, tree_view);
11351
11352   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11353     {
11354       GList *list;
11355
11356       _gtk_tree_view_column_realize_button (column);
11357
11358       for (list = tree_view->priv->columns; list; list = list->next)
11359         {
11360           column = GTK_TREE_VIEW_COLUMN (list->data);
11361           if (column->visible)
11362             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11363         }
11364       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11365     }
11366
11367   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11368
11369   return tree_view->priv->n_columns;
11370 }
11371
11372 /**
11373  * gtk_tree_view_insert_column_with_attributes:
11374  * @tree_view: A #GtkTreeView
11375  * @position: The position to insert the new column in.
11376  * @title: The title to set the header to.
11377  * @cell: The #GtkCellRenderer.
11378  * @Varargs: A %NULL-terminated list of attributes.
11379  *
11380  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11381  * @position.  If @position is -1, then the newly created column is inserted at
11382  * the end.  The column is initialized with the attributes given. If @tree_view
11383  * has "fixed_height" mode enabled, then the new column will have its sizing
11384  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11385  *
11386  * Return value: The number of columns in @tree_view after insertion.
11387  **/
11388 gint
11389 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11390                                              gint             position,
11391                                              const gchar     *title,
11392                                              GtkCellRenderer *cell,
11393                                              ...)
11394 {
11395   GtkTreeViewColumn *column;
11396   gchar *attribute;
11397   va_list args;
11398   gint column_id;
11399
11400   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11401
11402   column = gtk_tree_view_column_new ();
11403   if (tree_view->priv->fixed_height_mode)
11404     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11405
11406   gtk_tree_view_column_set_title (column, title);
11407   gtk_tree_view_column_pack_start (column, cell, TRUE);
11408
11409   va_start (args, cell);
11410
11411   attribute = va_arg (args, gchar *);
11412
11413   while (attribute != NULL)
11414     {
11415       column_id = va_arg (args, gint);
11416       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11417       attribute = va_arg (args, gchar *);
11418     }
11419
11420   va_end (args);
11421
11422   gtk_tree_view_insert_column (tree_view, column, position);
11423
11424   return tree_view->priv->n_columns;
11425 }
11426
11427 /**
11428  * gtk_tree_view_insert_column_with_data_func:
11429  * @tree_view: a #GtkTreeView
11430  * @position: Position to insert, -1 for append
11431  * @title: column title
11432  * @cell: cell renderer for column
11433  * @func: function to set attributes of cell renderer
11434  * @data: data for @func
11435  * @dnotify: destroy notifier for @data
11436  *
11437  * Convenience function that inserts a new column into the #GtkTreeView
11438  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11439  * attributes (normally using data from the model). See also
11440  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11441  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11442  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11443  *
11444  * Return value: number of columns in the tree view post-insert
11445  **/
11446 gint
11447 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11448                                              gint                       position,
11449                                              const gchar               *title,
11450                                              GtkCellRenderer           *cell,
11451                                              GtkTreeCellDataFunc        func,
11452                                              gpointer                   data,
11453                                              GDestroyNotify             dnotify)
11454 {
11455   GtkTreeViewColumn *column;
11456
11457   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11458
11459   column = gtk_tree_view_column_new ();
11460   if (tree_view->priv->fixed_height_mode)
11461     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11462
11463   gtk_tree_view_column_set_title (column, title);
11464   gtk_tree_view_column_pack_start (column, cell, TRUE);
11465   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11466
11467   gtk_tree_view_insert_column (tree_view, column, position);
11468
11469   return tree_view->priv->n_columns;
11470 }
11471
11472 /**
11473  * gtk_tree_view_get_column:
11474  * @tree_view: A #GtkTreeView.
11475  * @n: The position of the column, counting from 0.
11476  *
11477  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11478  *
11479  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
11480  *     position is outside the range of columns.
11481  **/
11482 GtkTreeViewColumn *
11483 gtk_tree_view_get_column (GtkTreeView *tree_view,
11484                           gint         n)
11485 {
11486   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11487
11488   if (n < 0 || n >= tree_view->priv->n_columns)
11489     return NULL;
11490
11491   if (tree_view->priv->columns == NULL)
11492     return NULL;
11493
11494   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11495 }
11496
11497 /**
11498  * gtk_tree_view_get_columns:
11499  * @tree_view: A #GtkTreeView
11500  *
11501  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11502  * The returned list must be freed with g_list_free ().
11503  *
11504  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11505  **/
11506 GList *
11507 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11508 {
11509   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11510
11511   return g_list_copy (tree_view->priv->columns);
11512 }
11513
11514 /**
11515  * gtk_tree_view_move_column_after:
11516  * @tree_view: A #GtkTreeView
11517  * @column: The #GtkTreeViewColumn to be moved.
11518  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11519  *
11520  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11521  * @column is placed in the first position.
11522  **/
11523 void
11524 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11525                                  GtkTreeViewColumn *column,
11526                                  GtkTreeViewColumn *base_column)
11527 {
11528   GList *column_list_el, *base_el = NULL;
11529
11530   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11531
11532   column_list_el = g_list_find (tree_view->priv->columns, column);
11533   g_return_if_fail (column_list_el != NULL);
11534
11535   if (base_column)
11536     {
11537       base_el = g_list_find (tree_view->priv->columns, base_column);
11538       g_return_if_fail (base_el != NULL);
11539     }
11540
11541   if (column_list_el->prev == base_el)
11542     return;
11543
11544   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11545   if (base_el == NULL)
11546     {
11547       column_list_el->prev = NULL;
11548       column_list_el->next = tree_view->priv->columns;
11549       if (column_list_el->next)
11550         column_list_el->next->prev = column_list_el;
11551       tree_view->priv->columns = column_list_el;
11552     }
11553   else
11554     {
11555       column_list_el->prev = base_el;
11556       column_list_el->next = base_el->next;
11557       if (column_list_el->next)
11558         column_list_el->next->prev = column_list_el;
11559       base_el->next = column_list_el;
11560     }
11561
11562   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11563     {
11564       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11565       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11566     }
11567
11568   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11569 }
11570
11571 /**
11572  * gtk_tree_view_set_expander_column:
11573  * @tree_view: A #GtkTreeView
11574  * @column: %NULL, or the column to draw the expander arrow at.
11575  *
11576  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11577  * If @column is %NULL, then the expander arrow is always at the first 
11578  * visible column.
11579  *
11580  * If you do not want expander arrow to appear in your tree, set the 
11581  * expander column to a hidden column.
11582  **/
11583 void
11584 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11585                                    GtkTreeViewColumn *column)
11586 {
11587   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11588   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11589
11590   if (tree_view->priv->expander_column != column)
11591     {
11592       GList *list;
11593
11594       if (column)
11595         {
11596           /* Confirm that column is in tree_view */
11597           for (list = tree_view->priv->columns; list; list = list->next)
11598             if (list->data == column)
11599               break;
11600           g_return_if_fail (list != NULL);
11601         }
11602
11603       tree_view->priv->expander_column = column;
11604       g_object_notify (G_OBJECT (tree_view), "expander-column");
11605     }
11606 }
11607
11608 /**
11609  * gtk_tree_view_get_expander_column:
11610  * @tree_view: A #GtkTreeView
11611  *
11612  * Returns the column that is the current expander column.
11613  * This column has the expander arrow drawn next to it.
11614  *
11615  * Return value: (transfer none): The expander column.
11616  **/
11617 GtkTreeViewColumn *
11618 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11619 {
11620   GList *list;
11621
11622   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11623
11624   for (list = tree_view->priv->columns; list; list = list->next)
11625     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11626       return (GtkTreeViewColumn *) list->data;
11627   return NULL;
11628 }
11629
11630
11631 /**
11632  * gtk_tree_view_set_column_drag_function:
11633  * @tree_view: A #GtkTreeView.
11634  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11635  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11636  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11637  *
11638  * Sets a user function for determining where a column may be dropped when
11639  * dragged.  This function is called on every column pair in turn at the
11640  * beginning of a column drag to determine where a drop can take place.  The
11641  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11642  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11643  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11644  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11645  * @tree_view reverts to the default behavior of allowing all columns to be
11646  * dropped everywhere.
11647  **/
11648 void
11649 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11650                                         GtkTreeViewColumnDropFunc  func,
11651                                         gpointer                   user_data,
11652                                         GDestroyNotify             destroy)
11653 {
11654   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11655
11656   if (tree_view->priv->column_drop_func_data_destroy)
11657     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11658
11659   tree_view->priv->column_drop_func = func;
11660   tree_view->priv->column_drop_func_data = user_data;
11661   tree_view->priv->column_drop_func_data_destroy = destroy;
11662 }
11663
11664 /**
11665  * gtk_tree_view_scroll_to_point:
11666  * @tree_view: a #GtkTreeView
11667  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11668  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11669  *
11670  * Scrolls the tree view such that the top-left corner of the visible
11671  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11672  * in tree coordinates.  The @tree_view must be realized before
11673  * this function is called.  If it isn't, you probably want to be
11674  * using gtk_tree_view_scroll_to_cell().
11675  *
11676  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11677  **/
11678 void
11679 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11680                                gint         tree_x,
11681                                gint         tree_y)
11682 {
11683   GtkAdjustment *hadj;
11684   GtkAdjustment *vadj;
11685
11686   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11687   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11688
11689   hadj = tree_view->priv->hadjustment;
11690   vadj = tree_view->priv->vadjustment;
11691
11692   if (tree_x != -1)
11693     gtk_adjustment_set_value (hadj, tree_x);
11694   if (tree_y != -1)
11695     gtk_adjustment_set_value (vadj, tree_y);
11696 }
11697
11698 /**
11699  * gtk_tree_view_scroll_to_cell:
11700  * @tree_view: A #GtkTreeView.
11701  * @path: (allow-none): The path of the row to move to, or %NULL.
11702  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11703  * @use_align: whether to use alignment arguments, or %FALSE.
11704  * @row_align: The vertical alignment of the row specified by @path.
11705  * @col_align: The horizontal alignment of the column specified by @column.
11706  *
11707  * Moves the alignments of @tree_view to the position specified by @column and
11708  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11709  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11710  * or @path need to be non-%NULL.  @row_align determines where the row is
11711  * placed, and @col_align determines where @column is placed.  Both are expected
11712  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11713  * right/bottom alignment, 0.5 means center.
11714  *
11715  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11716  * tree does the minimum amount of work to scroll the cell onto the screen.
11717  * This means that the cell will be scrolled to the edge closest to its current
11718  * position.  If the cell is currently visible on the screen, nothing is done.
11719  *
11720  * This function only works if the model is set, and @path is a valid row on the
11721  * model.  If the model changes before the @tree_view is realized, the centered
11722  * path will be modified to reflect this change.
11723  **/
11724 void
11725 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11726                               GtkTreePath       *path,
11727                               GtkTreeViewColumn *column,
11728                               gboolean           use_align,
11729                               gfloat             row_align,
11730                               gfloat             col_align)
11731 {
11732   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11733   g_return_if_fail (tree_view->priv->model != NULL);
11734   g_return_if_fail (tree_view->priv->tree != NULL);
11735   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11736   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11737   g_return_if_fail (path != NULL || column != NULL);
11738
11739 #if 0
11740   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11741            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11742 #endif
11743   row_align = CLAMP (row_align, 0.0, 1.0);
11744   col_align = CLAMP (col_align, 0.0, 1.0);
11745
11746
11747   /* Note: Despite the benefits that come from having one code path for the
11748    * scrolling code, we short-circuit validate_visible_area's immplementation as
11749    * it is much slower than just going to the point.
11750    */
11751   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11752       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11753       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
11754       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11755     {
11756       if (tree_view->priv->scroll_to_path)
11757         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11758
11759       tree_view->priv->scroll_to_path = NULL;
11760       tree_view->priv->scroll_to_column = NULL;
11761
11762       if (path)
11763         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11764       if (column)
11765         tree_view->priv->scroll_to_column = column;
11766       tree_view->priv->scroll_to_use_align = use_align;
11767       tree_view->priv->scroll_to_row_align = row_align;
11768       tree_view->priv->scroll_to_col_align = col_align;
11769
11770       install_presize_handler (tree_view);
11771     }
11772   else
11773     {
11774       GdkRectangle cell_rect;
11775       GdkRectangle vis_rect;
11776       gint dest_x, dest_y;
11777
11778       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11779       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11780
11781       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11782
11783       dest_x = vis_rect.x;
11784       dest_y = vis_rect.y;
11785
11786       if (column)
11787         {
11788           if (use_align)
11789             {
11790               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11791             }
11792           else
11793             {
11794               if (cell_rect.x < vis_rect.x)
11795                 dest_x = cell_rect.x;
11796               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11797                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11798             }
11799         }
11800
11801       if (path)
11802         {
11803           if (use_align)
11804             {
11805               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11806               dest_y = MAX (dest_y, 0);
11807             }
11808           else
11809             {
11810               if (cell_rect.y < vis_rect.y)
11811                 dest_y = cell_rect.y;
11812               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11813                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11814             }
11815         }
11816
11817       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11818     }
11819 }
11820
11821 /**
11822  * gtk_tree_view_row_activated:
11823  * @tree_view: A #GtkTreeView
11824  * @path: The #GtkTreePath to be activated.
11825  * @column: The #GtkTreeViewColumn to be activated.
11826  *
11827  * Activates the cell determined by @path and @column.
11828  **/
11829 void
11830 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11831                              GtkTreePath       *path,
11832                              GtkTreeViewColumn *column)
11833 {
11834   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11835
11836   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11837 }
11838
11839
11840 static void
11841 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11842                                           GtkRBNode *node,
11843                                           gpointer   data)
11844 {
11845   GtkTreeView *tree_view = data;
11846
11847   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11848       node->children)
11849     {
11850       GtkTreePath *path;
11851       GtkTreeIter iter;
11852
11853       path = _gtk_tree_view_find_path (tree_view, tree, node);
11854       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11855
11856       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11857
11858       gtk_tree_path_free (path);
11859     }
11860
11861   if (node->children)
11862     _gtk_rbtree_traverse (node->children,
11863                           node->children->root,
11864                           G_PRE_ORDER,
11865                           gtk_tree_view_expand_all_emission_helper,
11866                           tree_view);
11867 }
11868
11869 /**
11870  * gtk_tree_view_expand_all:
11871  * @tree_view: A #GtkTreeView.
11872  *
11873  * Recursively expands all nodes in the @tree_view.
11874  **/
11875 void
11876 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11877 {
11878   GtkTreePath *path;
11879   GtkRBTree *tree;
11880   GtkRBNode *node;
11881
11882   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11883
11884   if (tree_view->priv->tree == NULL)
11885     return;
11886
11887   path = gtk_tree_path_new_first ();
11888   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11889
11890   while (node)
11891     {
11892       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11893       node = _gtk_rbtree_next (tree, node);
11894       gtk_tree_path_next (path);
11895   }
11896
11897   gtk_tree_path_free (path);
11898 }
11899
11900 /* Timeout to animate the expander during expands and collapses */
11901 static gboolean
11902 expand_collapse_timeout (gpointer data)
11903 {
11904   return do_expand_collapse (data);
11905 }
11906
11907 static void
11908 add_expand_collapse_timeout (GtkTreeView *tree_view,
11909                              GtkRBTree   *tree,
11910                              GtkRBNode   *node,
11911                              gboolean     expand)
11912 {
11913   if (tree_view->priv->expand_collapse_timeout != 0)
11914     return;
11915
11916   tree_view->priv->expand_collapse_timeout =
11917       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11918   tree_view->priv->expanded_collapsed_tree = tree;
11919   tree_view->priv->expanded_collapsed_node = node;
11920
11921   if (expand)
11922     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11923   else
11924     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11925 }
11926
11927 static void
11928 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11929 {
11930   if (tree_view->priv->expand_collapse_timeout)
11931     {
11932       g_source_remove (tree_view->priv->expand_collapse_timeout);
11933       tree_view->priv->expand_collapse_timeout = 0;
11934     }
11935
11936   if (tree_view->priv->expanded_collapsed_node != NULL)
11937     {
11938       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11939       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11940
11941       tree_view->priv->expanded_collapsed_node = NULL;
11942     }
11943 }
11944
11945 static void
11946 cancel_arrow_animation (GtkTreeView *tree_view)
11947 {
11948   if (tree_view->priv->expand_collapse_timeout)
11949     {
11950       while (do_expand_collapse (tree_view));
11951
11952       remove_expand_collapse_timeout (tree_view);
11953     }
11954 }
11955
11956 static gboolean
11957 do_expand_collapse (GtkTreeView *tree_view)
11958 {
11959   GtkRBNode *node;
11960   GtkRBTree *tree;
11961   gboolean expanding;
11962   gboolean redraw;
11963
11964   redraw = FALSE;
11965   expanding = TRUE;
11966
11967   node = tree_view->priv->expanded_collapsed_node;
11968   tree = tree_view->priv->expanded_collapsed_tree;
11969
11970   if (node->children == NULL)
11971     expanding = FALSE;
11972
11973   if (expanding)
11974     {
11975       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11976         {
11977           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11978           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11979
11980           redraw = TRUE;
11981
11982         }
11983       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11984         {
11985           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11986
11987           redraw = TRUE;
11988         }
11989     }
11990   else
11991     {
11992       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11993         {
11994           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11995           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11996
11997           redraw = TRUE;
11998         }
11999       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12000         {
12001           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12002
12003           redraw = TRUE;
12004
12005         }
12006     }
12007
12008   if (redraw)
12009     {
12010       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
12011
12012       return TRUE;
12013     }
12014
12015   return FALSE;
12016 }
12017
12018 /**
12019  * gtk_tree_view_collapse_all:
12020  * @tree_view: A #GtkTreeView.
12021  *
12022  * Recursively collapses all visible, expanded nodes in @tree_view.
12023  **/
12024 void
12025 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12026 {
12027   GtkRBTree *tree;
12028   GtkRBNode *node;
12029   GtkTreePath *path;
12030   gint *indices;
12031
12032   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12033
12034   if (tree_view->priv->tree == NULL)
12035     return;
12036
12037   path = gtk_tree_path_new ();
12038   gtk_tree_path_down (path);
12039   indices = gtk_tree_path_get_indices (path);
12040
12041   tree = tree_view->priv->tree;
12042   node = tree->root;
12043   while (node && node->left != tree->nil)
12044     node = node->left;
12045
12046   while (node)
12047     {
12048       if (node->children)
12049         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12050       indices[0]++;
12051       node = _gtk_rbtree_next (tree, node);
12052     }
12053
12054   gtk_tree_path_free (path);
12055 }
12056
12057 /**
12058  * gtk_tree_view_expand_to_path:
12059  * @tree_view: A #GtkTreeView.
12060  * @path: path to a row.
12061  *
12062  * Expands the row at @path. This will also expand all parent rows of
12063  * @path as necessary.
12064  *
12065  * Since: 2.2
12066  **/
12067 void
12068 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12069                               GtkTreePath *path)
12070 {
12071   gint i, depth;
12072   gint *indices;
12073   GtkTreePath *tmp;
12074
12075   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12076   g_return_if_fail (path != NULL);
12077
12078   depth = gtk_tree_path_get_depth (path);
12079   indices = gtk_tree_path_get_indices (path);
12080
12081   tmp = gtk_tree_path_new ();
12082   g_return_if_fail (tmp != NULL);
12083
12084   for (i = 0; i < depth; i++)
12085     {
12086       gtk_tree_path_append_index (tmp, indices[i]);
12087       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12088     }
12089
12090   gtk_tree_path_free (tmp);
12091 }
12092
12093 /* FIXME the bool return values for expand_row and collapse_row are
12094  * not analagous; they should be TRUE if the row had children and
12095  * was not already in the requested state.
12096  */
12097
12098
12099 static gboolean
12100 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12101                                GtkTreePath *path,
12102                                GtkRBTree   *tree,
12103                                GtkRBNode   *node,
12104                                gboolean     open_all,
12105                                gboolean     animate)
12106 {
12107   GtkTreeIter iter;
12108   GtkTreeIter temp;
12109   gboolean expand;
12110
12111   if (animate)
12112     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12113                   "gtk-enable-animations", &animate,
12114                   NULL);
12115
12116   remove_auto_expand_timeout (tree_view);
12117
12118   if (node->children && !open_all)
12119     return FALSE;
12120
12121   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12122     return FALSE;
12123
12124   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12125   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12126     return FALSE;
12127
12128
12129    if (node->children && open_all)
12130     {
12131       gboolean retval = FALSE;
12132       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12133
12134       gtk_tree_path_append_index (tmp_path, 0);
12135       tree = node->children;
12136       node = tree->root;
12137       while (node->left != tree->nil)
12138         node = node->left;
12139       /* try to expand the children */
12140       do
12141         {
12142          gboolean t;
12143          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12144                                             TRUE, animate);
12145          if (t)
12146            retval = TRUE;
12147
12148          gtk_tree_path_next (tmp_path);
12149          node = _gtk_rbtree_next (tree, node);
12150        }
12151       while (node != NULL);
12152
12153       gtk_tree_path_free (tmp_path);
12154
12155       return retval;
12156     }
12157
12158   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12159
12160   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12161     return FALSE;
12162
12163   if (expand)
12164     return FALSE;
12165
12166   node->children = _gtk_rbtree_new ();
12167   node->children->parent_tree = tree;
12168   node->children->parent_node = node;
12169
12170   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12171
12172   gtk_tree_view_build_tree (tree_view,
12173                             node->children,
12174                             &temp,
12175                             gtk_tree_path_get_depth (path) + 1,
12176                             open_all);
12177
12178   remove_expand_collapse_timeout (tree_view);
12179
12180   if (animate)
12181     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12182
12183   install_presize_handler (tree_view);
12184
12185   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12186   if (open_all && node->children)
12187     {
12188       _gtk_rbtree_traverse (node->children,
12189                             node->children->root,
12190                             G_PRE_ORDER,
12191                             gtk_tree_view_expand_all_emission_helper,
12192                             tree_view);
12193     }
12194   return TRUE;
12195 }
12196
12197
12198 /**
12199  * gtk_tree_view_expand_row:
12200  * @tree_view: a #GtkTreeView
12201  * @path: path to a row
12202  * @open_all: whether to recursively expand, or just expand immediate children
12203  *
12204  * Opens the row so its children are visible.
12205  *
12206  * Return value: %TRUE if the row existed and had children
12207  **/
12208 gboolean
12209 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12210                           GtkTreePath *path,
12211                           gboolean     open_all)
12212 {
12213   GtkRBTree *tree;
12214   GtkRBNode *node;
12215
12216   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12217   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12218   g_return_val_if_fail (path != NULL, FALSE);
12219
12220   if (_gtk_tree_view_find_node (tree_view,
12221                                 path,
12222                                 &tree,
12223                                 &node))
12224     return FALSE;
12225
12226   if (tree != NULL)
12227     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12228   else
12229     return FALSE;
12230 }
12231
12232 static gboolean
12233 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12234                                  GtkTreePath *path,
12235                                  GtkRBTree   *tree,
12236                                  GtkRBNode   *node,
12237                                  gboolean     animate)
12238 {
12239   GtkTreeIter iter;
12240   GtkTreeIter children;
12241   gboolean collapse;
12242   gint x, y;
12243   GList *list;
12244   GdkWindow *child, *parent;
12245
12246   if (animate)
12247     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12248                   "gtk-enable-animations", &animate,
12249                   NULL);
12250
12251   remove_auto_expand_timeout (tree_view);
12252
12253   if (node->children == NULL)
12254     return FALSE;
12255
12256   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12257
12258   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12259
12260   if (collapse)
12261     return FALSE;
12262
12263   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12264    * a chance to prelight the correct node below */
12265
12266   if (tree_view->priv->prelight_tree)
12267     {
12268       GtkRBTree *parent_tree;
12269       GtkRBNode *parent_node;
12270
12271       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12272       parent_node = tree_view->priv->prelight_tree->parent_node;
12273       while (parent_tree)
12274         {
12275           if (parent_tree == tree && parent_node == node)
12276             {
12277               ensure_unprelighted (tree_view);
12278               break;
12279             }
12280           parent_node = parent_tree->parent_node;
12281           parent_tree = parent_tree->parent_tree;
12282         }
12283     }
12284
12285   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12286
12287   for (list = tree_view->priv->columns; list; list = list->next)
12288     {
12289       GtkTreeViewColumn *column = list->data;
12290
12291       if (column->visible == FALSE)
12292         continue;
12293       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12294         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12295     }
12296
12297   if (tree_view->priv->destroy_count_func)
12298     {
12299       GtkTreePath *child_path;
12300       gint child_count = 0;
12301       child_path = gtk_tree_path_copy (path);
12302       gtk_tree_path_down (child_path);
12303       if (node->children)
12304         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12305       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12306       gtk_tree_path_free (child_path);
12307     }
12308
12309   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12310     {
12311       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12312
12313       if (gtk_tree_path_is_ancestor (path, cursor_path))
12314         {
12315           gtk_tree_row_reference_free (tree_view->priv->cursor);
12316           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12317                                                                       tree_view->priv->model,
12318                                                                       path);
12319         }
12320       gtk_tree_path_free (cursor_path);
12321     }
12322
12323   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12324     {
12325       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12326       if (gtk_tree_path_is_ancestor (path, anchor_path))
12327         {
12328           gtk_tree_row_reference_free (tree_view->priv->anchor);
12329           tree_view->priv->anchor = NULL;
12330         }
12331       gtk_tree_path_free (anchor_path);
12332     }
12333
12334   /* Stop a pending double click */
12335   tree_view->priv->last_button_x = -1;
12336   tree_view->priv->last_button_y = -1;
12337
12338   remove_expand_collapse_timeout (tree_view);
12339
12340   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12341     {
12342       _gtk_rbtree_remove (node->children);
12343       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12344     }
12345   else
12346     _gtk_rbtree_remove (node->children);
12347   
12348   if (animate)
12349     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12350   
12351   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12352     {
12353       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12354     }
12355
12356   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12357
12358   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12359     {
12360       /* now that we've collapsed all rows, we want to try to set the prelight
12361        * again. To do this, we fake a motion event and send it to ourselves. */
12362
12363       child = tree_view->priv->bin_window;
12364       parent = gdk_window_get_parent (child);
12365
12366       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12367         {
12368           GdkEventMotion event;
12369           gint child_x, child_y;
12370
12371           gdk_window_get_position (child, &child_x, &child_y);
12372
12373           event.window = tree_view->priv->bin_window;
12374           event.x = x - child_x;
12375           event.y = y - child_y;
12376
12377           /* despite the fact this isn't a real event, I'm almost positive it will
12378            * never trigger a drag event.  maybe_drag is the only function that uses
12379            * more than just event.x and event.y. */
12380           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12381         }
12382     }
12383
12384   return TRUE;
12385 }
12386
12387 /**
12388  * gtk_tree_view_collapse_row:
12389  * @tree_view: a #GtkTreeView
12390  * @path: path to a row in the @tree_view
12391  *
12392  * Collapses a row (hides its child rows, if they exist).
12393  *
12394  * Return value: %TRUE if the row was collapsed.
12395  **/
12396 gboolean
12397 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12398                             GtkTreePath *path)
12399 {
12400   GtkRBTree *tree;
12401   GtkRBNode *node;
12402
12403   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12404   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12405   g_return_val_if_fail (path != NULL, FALSE);
12406
12407   if (_gtk_tree_view_find_node (tree_view,
12408                                 path,
12409                                 &tree,
12410                                 &node))
12411     return FALSE;
12412
12413   if (tree == NULL || node->children == NULL)
12414     return FALSE;
12415
12416   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12417 }
12418
12419 static void
12420 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12421                                         GtkRBTree              *tree,
12422                                         GtkTreePath            *path,
12423                                         GtkTreeViewMappingFunc  func,
12424                                         gpointer                user_data)
12425 {
12426   GtkRBNode *node;
12427
12428   if (tree == NULL || tree->root == NULL)
12429     return;
12430
12431   node = tree->root;
12432
12433   while (node && node->left != tree->nil)
12434     node = node->left;
12435
12436   while (node)
12437     {
12438       if (node->children)
12439         {
12440           (* func) (tree_view, path, user_data);
12441           gtk_tree_path_down (path);
12442           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12443           gtk_tree_path_up (path);
12444         }
12445       gtk_tree_path_next (path);
12446       node = _gtk_rbtree_next (tree, node);
12447     }
12448 }
12449
12450 /**
12451  * gtk_tree_view_map_expanded_rows:
12452  * @tree_view: A #GtkTreeView
12453  * @func: (scope call): A function to be called
12454  * @data: User data to be passed to the function.
12455  *
12456  * Calls @func on all expanded rows.
12457  **/
12458 void
12459 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12460                                  GtkTreeViewMappingFunc  func,
12461                                  gpointer                user_data)
12462 {
12463   GtkTreePath *path;
12464
12465   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12466   g_return_if_fail (func != NULL);
12467
12468   path = gtk_tree_path_new_first ();
12469
12470   gtk_tree_view_map_expanded_rows_helper (tree_view,
12471                                           tree_view->priv->tree,
12472                                           path, func, user_data);
12473
12474   gtk_tree_path_free (path);
12475 }
12476
12477 /**
12478  * gtk_tree_view_row_expanded:
12479  * @tree_view: A #GtkTreeView.
12480  * @path: A #GtkTreePath to test expansion state.
12481  *
12482  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12483  *
12484  * Return value: %TRUE if #path is expanded.
12485  **/
12486 gboolean
12487 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12488                             GtkTreePath *path)
12489 {
12490   GtkRBTree *tree;
12491   GtkRBNode *node;
12492
12493   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12494   g_return_val_if_fail (path != NULL, FALSE);
12495
12496   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12497
12498   if (node == NULL)
12499     return FALSE;
12500
12501   return (node->children != NULL);
12502 }
12503
12504 /**
12505  * gtk_tree_view_get_reorderable:
12506  * @tree_view: a #GtkTreeView
12507  *
12508  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12509  * gtk_tree_view_set_reorderable().
12510  *
12511  * Return value: %TRUE if the tree can be reordered.
12512  **/
12513 gboolean
12514 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12515 {
12516   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12517
12518   return tree_view->priv->reorderable;
12519 }
12520
12521 /**
12522  * gtk_tree_view_set_reorderable:
12523  * @tree_view: A #GtkTreeView.
12524  * @reorderable: %TRUE, if the tree can be reordered.
12525  *
12526  * This function is a convenience function to allow you to reorder
12527  * models that support the #GtkDragSourceIface and the
12528  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12529  * these.  If @reorderable is %TRUE, then the user can reorder the
12530  * model by dragging and dropping rows. The developer can listen to
12531  * these changes by connecting to the model's row_inserted and
12532  * row_deleted signals. The reordering is implemented by setting up
12533  * the tree view as a drag source and destination. Therefore, drag and
12534  * drop can not be used in a reorderable view for any other purpose.
12535  *
12536  * This function does not give you any degree of control over the order -- any
12537  * reordering is allowed.  If more control is needed, you should probably
12538  * handle drag and drop manually.
12539  **/
12540 void
12541 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12542                                gboolean     reorderable)
12543 {
12544   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12545
12546   reorderable = reorderable != FALSE;
12547
12548   if (tree_view->priv->reorderable == reorderable)
12549     return;
12550
12551   if (reorderable)
12552     {
12553       const GtkTargetEntry row_targets[] = {
12554         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12555       };
12556
12557       gtk_tree_view_enable_model_drag_source (tree_view,
12558                                               GDK_BUTTON1_MASK,
12559                                               row_targets,
12560                                               G_N_ELEMENTS (row_targets),
12561                                               GDK_ACTION_MOVE);
12562       gtk_tree_view_enable_model_drag_dest (tree_view,
12563                                             row_targets,
12564                                             G_N_ELEMENTS (row_targets),
12565                                             GDK_ACTION_MOVE);
12566     }
12567   else
12568     {
12569       gtk_tree_view_unset_rows_drag_source (tree_view);
12570       gtk_tree_view_unset_rows_drag_dest (tree_view);
12571     }
12572
12573   tree_view->priv->reorderable = reorderable;
12574
12575   g_object_notify (G_OBJECT (tree_view), "reorderable");
12576 }
12577
12578 static void
12579 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12580                                GtkTreePath     *path,
12581                                gboolean         clear_and_select,
12582                                gboolean         clamp_node)
12583 {
12584   GtkRBTree *tree = NULL;
12585   GtkRBNode *node = NULL;
12586
12587   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12588     {
12589       GtkTreePath *cursor_path;
12590       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12591       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12592       gtk_tree_path_free (cursor_path);
12593     }
12594
12595   gtk_tree_row_reference_free (tree_view->priv->cursor);
12596   tree_view->priv->cursor = NULL;
12597
12598   /* One cannot set the cursor on a separator.   Also, if
12599    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12600    * before finding the tree and node belonging to path.  The
12601    * path maps to a non-existing path and we will silently bail out.
12602    * We unset tree and node to avoid further processing.
12603    */
12604   if (!row_is_separator (tree_view, NULL, path)
12605       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12606     {
12607       tree_view->priv->cursor =
12608           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12609                                             tree_view->priv->model,
12610                                             path);
12611     }
12612   else
12613     {
12614       tree = NULL;
12615       node = NULL;
12616     }
12617
12618   if (tree != NULL)
12619     {
12620       GtkRBTree *new_tree = NULL;
12621       GtkRBNode *new_node = NULL;
12622
12623       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12624         {
12625           GtkTreeSelectMode mode = 0;
12626
12627           if (tree_view->priv->ctrl_pressed)
12628             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12629           if (tree_view->priv->shift_pressed)
12630             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12631
12632           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12633                                                     node, tree, path, mode,
12634                                                     FALSE);
12635         }
12636
12637       /* We have to re-find tree and node here again, somebody might have
12638        * cleared the node or the whole tree in the GtkTreeSelection::changed
12639        * callback. If the nodes differ we bail out here.
12640        */
12641       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12642
12643       if (tree != new_tree || node != new_node)
12644         return;
12645
12646       if (clamp_node)
12647         {
12648           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12649           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12650         }
12651     }
12652
12653   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12654 }
12655
12656 /**
12657  * gtk_tree_view_get_cursor:
12658  * @tree_view: A #GtkTreeView
12659  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12660  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12661  *
12662  * Fills in @path and @focus_column with the current path and focus column.  If
12663  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12664  * currently has focus, then *@focus_column will be %NULL.
12665  *
12666  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12667  * you are done with it.
12668  **/
12669 void
12670 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12671                           GtkTreePath       **path,
12672                           GtkTreeViewColumn **focus_column)
12673 {
12674   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12675
12676   if (path)
12677     {
12678       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12679         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12680       else
12681         *path = NULL;
12682     }
12683
12684   if (focus_column)
12685     {
12686       *focus_column = tree_view->priv->focus_column;
12687     }
12688 }
12689
12690 /**
12691  * gtk_tree_view_set_cursor:
12692  * @tree_view: A #GtkTreeView
12693  * @path: A #GtkTreePath
12694  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12695  * @start_editing: %TRUE if the specified cell should start being edited.
12696  *
12697  * Sets the current keyboard focus to be at @path, and selects it.  This is
12698  * useful when you want to focus the user's attention on a particular row.  If
12699  * @focus_column is not %NULL, then focus is given to the column specified by 
12700  * it. Additionally, if @focus_column is specified, and @start_editing is 
12701  * %TRUE, then editing should be started in the specified cell.  
12702  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12703  * in order to give keyboard focus to the widget.  Please note that editing 
12704  * can only happen when the widget is realized.
12705  *
12706  * If @path is invalid for @model, the current cursor (if any) will be unset
12707  * and the function will return without failing.
12708  **/
12709 void
12710 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12711                           GtkTreePath       *path,
12712                           GtkTreeViewColumn *focus_column,
12713                           gboolean           start_editing)
12714 {
12715   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12716                                     NULL, start_editing);
12717 }
12718
12719 /**
12720  * gtk_tree_view_set_cursor_on_cell:
12721  * @tree_view: A #GtkTreeView
12722  * @path: A #GtkTreePath
12723  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12724  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12725  * @start_editing: %TRUE if the specified cell should start being edited.
12726  *
12727  * Sets the current keyboard focus to be at @path, and selects it.  This is
12728  * useful when you want to focus the user's attention on a particular row.  If
12729  * @focus_column is not %NULL, then focus is given to the column specified by
12730  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12731  * contains 2 or more editable or activatable cells, then focus is given to
12732  * the cell specified by @focus_cell. Additionally, if @focus_column is
12733  * specified, and @start_editing is %TRUE, then editing should be started in
12734  * the specified cell.  This function is often followed by
12735  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12736  * widget.  Please note that editing can only happen when the widget is
12737  * realized.
12738  *
12739  * If @path is invalid for @model, the current cursor (if any) will be unset
12740  * and the function will return without failing.
12741  *
12742  * Since: 2.2
12743  **/
12744 void
12745 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12746                                   GtkTreePath       *path,
12747                                   GtkTreeViewColumn *focus_column,
12748                                   GtkCellRenderer   *focus_cell,
12749                                   gboolean           start_editing)
12750 {
12751   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12752   g_return_if_fail (path != NULL);
12753   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12754
12755   if (!tree_view->priv->model)
12756     return;
12757
12758   if (focus_cell)
12759     {
12760       g_return_if_fail (focus_column);
12761       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12762     }
12763
12764   /* cancel the current editing, if it exists */
12765   if (tree_view->priv->edited_column &&
12766       tree_view->priv->edited_column->editable_widget)
12767     gtk_tree_view_stop_editing (tree_view, TRUE);
12768
12769   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12770
12771   if (focus_column && focus_column->visible)
12772     {
12773       GList *list;
12774       gboolean column_in_tree = FALSE;
12775
12776       for (list = tree_view->priv->columns; list; list = list->next)
12777         if (list->data == focus_column)
12778           {
12779             column_in_tree = TRUE;
12780             break;
12781           }
12782       g_return_if_fail (column_in_tree);
12783       tree_view->priv->focus_column = focus_column;
12784       if (focus_cell)
12785         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12786       if (start_editing)
12787         gtk_tree_view_start_editing (tree_view, path);
12788     }
12789 }
12790
12791 /**
12792  * gtk_tree_view_get_bin_window:
12793  * @tree_view: A #GtkTreeView
12794  *
12795  * Returns the window that @tree_view renders to.
12796  * This is used primarily to compare to <literal>event->window</literal>
12797  * to confirm that the event on @tree_view is on the right window.
12798  *
12799  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
12800  *     hasn't been realized yet
12801  **/
12802 GdkWindow *
12803 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12804 {
12805   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12806
12807   return tree_view->priv->bin_window;
12808 }
12809
12810 /**
12811  * gtk_tree_view_get_path_at_pos:
12812  * @tree_view: A #GtkTreeView.
12813  * @x: The x position to be identified (relative to bin_window).
12814  * @y: The y position to be identified (relative to bin_window).
12815  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12816  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12817  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12818  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12819  *
12820  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12821  * (please see gtk_tree_view_get_bin_window()).
12822  * That is, @x and @y are relative to an events coordinates. @x and @y must
12823  * come from an event on the @tree_view only where <literal>event->window ==
12824  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12825  * things like popup menus. If @path is non-%NULL, then it will be filled
12826  * with the #GtkTreePath at that point.  This path should be freed with
12827  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12828  * with the column at that point.  @cell_x and @cell_y return the coordinates
12829  * relative to the cell background (i.e. the @background_area passed to
12830  * gtk_cell_renderer_render()).  This function is only meaningful if
12831  * @tree_view is realized.  Therefore this function will always return %FALSE
12832  * if @tree_view is not realized or does not have a model.
12833  *
12834  * For converting widget coordinates (eg. the ones you get from
12835  * GtkWidget::query-tooltip), please see
12836  * gtk_tree_view_convert_widget_to_bin_window_coords().
12837  *
12838  * Return value: %TRUE if a row exists at that coordinate.
12839  **/
12840 gboolean
12841 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12842                                gint                x,
12843                                gint                y,
12844                                GtkTreePath       **path,
12845                                GtkTreeViewColumn **column,
12846                                gint               *cell_x,
12847                                gint               *cell_y)
12848 {
12849   GtkRBTree *tree;
12850   GtkRBNode *node;
12851   gint y_offset;
12852
12853   g_return_val_if_fail (tree_view != NULL, FALSE);
12854
12855   if (path)
12856     *path = NULL;
12857   if (column)
12858     *column = NULL;
12859
12860   if (tree_view->priv->bin_window == NULL)
12861     return FALSE;
12862
12863   if (tree_view->priv->tree == NULL)
12864     return FALSE;
12865
12866   if (x > tree_view->priv->hadjustment->upper)
12867     return FALSE;
12868
12869   if (x < 0 || y < 0)
12870     return FALSE;
12871
12872   if (column || cell_x)
12873     {
12874       GtkTreeViewColumn *tmp_column;
12875       GtkTreeViewColumn *last_column = NULL;
12876       GList *list;
12877       gint remaining_x = x;
12878       gboolean found = FALSE;
12879       gboolean rtl;
12880
12881       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12882       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12883            list;
12884            list = (rtl ? list->prev : list->next))
12885         {
12886           tmp_column = list->data;
12887
12888           if (tmp_column->visible == FALSE)
12889             continue;
12890
12891           last_column = tmp_column;
12892           if (remaining_x <= tmp_column->width)
12893             {
12894               found = TRUE;
12895
12896               if (column)
12897                 *column = tmp_column;
12898
12899               if (cell_x)
12900                 *cell_x = remaining_x;
12901
12902               break;
12903             }
12904           remaining_x -= tmp_column->width;
12905         }
12906
12907       /* If found is FALSE and there is a last_column, then it the remainder
12908        * space is in that area
12909        */
12910       if (!found)
12911         {
12912           if (last_column)
12913             {
12914               if (column)
12915                 *column = last_column;
12916               
12917               if (cell_x)
12918                 *cell_x = last_column->width + remaining_x;
12919             }
12920           else
12921             {
12922               return FALSE;
12923             }
12924         }
12925     }
12926
12927   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12928                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12929                                       &tree, &node);
12930
12931   if (tree == NULL)
12932     return FALSE;
12933
12934   if (cell_y)
12935     *cell_y = y_offset;
12936
12937   if (path)
12938     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12939
12940   return TRUE;
12941 }
12942
12943
12944 /**
12945  * gtk_tree_view_get_cell_area:
12946  * @tree_view: a #GtkTreeView
12947  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12948  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12949  * @rect: rectangle to fill with cell rect
12950  *
12951  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12952  * row specified by @path and the column specified by @column.  If @path is
12953  * %NULL, or points to a path not currently displayed, the @y and @height fields
12954  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12955  * fields will be filled with 0.  The sum of all cell rects does not cover the
12956  * entire tree; there are extra pixels in between rows, for example. The
12957  * returned rectangle is equivalent to the @cell_area passed to
12958  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12959  * realized.
12960  **/
12961 void
12962 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12963                              GtkTreePath        *path,
12964                              GtkTreeViewColumn  *column,
12965                              GdkRectangle       *rect)
12966 {
12967   GtkAllocation allocation;
12968   GtkRBTree *tree = NULL;
12969   GtkRBNode *node = NULL;
12970   gint vertical_separator;
12971   gint horizontal_separator;
12972
12973   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12974   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12975   g_return_if_fail (rect != NULL);
12976   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12977   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12978
12979   gtk_widget_style_get (GTK_WIDGET (tree_view),
12980                         "vertical-separator", &vertical_separator,
12981                         "horizontal-separator", &horizontal_separator,
12982                         NULL);
12983
12984   rect->x = 0;
12985   rect->y = 0;
12986   rect->width = 0;
12987   rect->height = 0;
12988
12989   if (column)
12990     {
12991       gtk_widget_get_allocation (column->button, &allocation);
12992       rect->x = allocation.x + horizontal_separator/2;
12993       rect->width = allocation.width - horizontal_separator;
12994     }
12995
12996   if (path)
12997     {
12998       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12999
13000       /* Get vertical coords */
13001       if ((!ret && tree == NULL) || ret)
13002         return;
13003
13004       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
13005       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
13006
13007       if (column &&
13008           gtk_tree_view_is_expander_column (tree_view, column))
13009         {
13010           gint depth = gtk_tree_path_get_depth (path);
13011           gboolean rtl;
13012
13013           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13014
13015           if (!rtl)
13016             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13017           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13018
13019           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
13020             {
13021               if (!rtl)
13022                 rect->x += depth * tree_view->priv->expander_size;
13023               rect->width -= depth * tree_view->priv->expander_size;
13024             }
13025
13026           rect->width = MAX (rect->width, 0);
13027         }
13028     }
13029 }
13030
13031 /**
13032  * gtk_tree_view_get_background_area:
13033  * @tree_view: a #GtkTreeView
13034  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13035  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13036  * @rect: rectangle to fill with cell background rect
13037  *
13038  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13039  * row specified by @path and the column specified by @column.  If @path is
13040  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13041  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13042  * fields will be filled with 0.  The returned rectangle is equivalent to the
13043  * @background_area passed to gtk_cell_renderer_render().  These background
13044  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13045  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13046  * itself, excluding surrounding borders and the tree expander area.
13047  *
13048  **/
13049 void
13050 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13051                                    GtkTreePath        *path,
13052                                    GtkTreeViewColumn  *column,
13053                                    GdkRectangle       *rect)
13054 {
13055   GtkRBTree *tree = NULL;
13056   GtkRBNode *node = NULL;
13057
13058   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13059   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13060   g_return_if_fail (rect != NULL);
13061
13062   rect->x = 0;
13063   rect->y = 0;
13064   rect->width = 0;
13065   rect->height = 0;
13066
13067   if (path)
13068     {
13069       /* Get vertical coords */
13070
13071       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13072           tree == NULL)
13073         return;
13074
13075       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13076
13077       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13078     }
13079
13080   if (column)
13081     {
13082       gint x2 = 0;
13083
13084       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13085       rect->width = x2 - rect->x;
13086     }
13087 }
13088
13089 /**
13090  * gtk_tree_view_get_visible_rect:
13091  * @tree_view: a #GtkTreeView
13092  * @visible_rect: rectangle to fill
13093  *
13094  * Fills @visible_rect with the currently-visible region of the
13095  * buffer, in tree coordinates. Convert to bin_window coordinates with
13096  * gtk_tree_view_convert_tree_to_bin_window_coords().
13097  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13098  * scrollable area of the tree.
13099  **/
13100 void
13101 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13102                                 GdkRectangle *visible_rect)
13103 {
13104   GtkAllocation allocation;
13105   GtkWidget *widget;
13106
13107   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13108
13109   widget = GTK_WIDGET (tree_view);
13110
13111   if (visible_rect)
13112     {
13113       gtk_widget_get_allocation (widget, &allocation);
13114       visible_rect->x = tree_view->priv->hadjustment->value;
13115       visible_rect->y = tree_view->priv->vadjustment->value;
13116       visible_rect->width = allocation.width;
13117       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13118     }
13119 }
13120
13121 /**
13122  * gtk_tree_view_convert_widget_to_tree_coords:
13123  * @tree_view: a #GtkTreeView
13124  * @wx: X coordinate relative to the widget
13125  * @wy: Y coordinate relative to the widget
13126  * @tx: return location for tree X coordinate
13127  * @ty: return location for tree Y coordinate
13128  *
13129  * Converts widget coordinates to coordinates for the
13130  * tree (the full scrollable area of the tree).
13131  *
13132  * Since: 2.12
13133  **/
13134 void
13135 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13136                                              gint         wx,
13137                                              gint         wy,
13138                                              gint        *tx,
13139                                              gint        *ty)
13140 {
13141   gint x, y;
13142
13143   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13144
13145   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13146                                                      wx, wy,
13147                                                      &x, &y);
13148   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13149                                                    x, y,
13150                                                    tx, ty);
13151 }
13152
13153 /**
13154  * gtk_tree_view_convert_tree_to_widget_coords:
13155  * @tree_view: a #GtkTreeView
13156  * @tx: X coordinate relative to the tree
13157  * @ty: Y coordinate relative to the tree
13158  * @wx: return location for widget X coordinate
13159  * @wy: return location for widget Y coordinate
13160  *
13161  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13162  * to widget coordinates.
13163  *
13164  * Since: 2.12
13165  **/
13166 void
13167 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13168                                              gint         tx,
13169                                              gint         ty,
13170                                              gint        *wx,
13171                                              gint        *wy)
13172 {
13173   gint x, y;
13174
13175   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13176
13177   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13178                                                    tx, ty,
13179                                                    &x, &y);
13180   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13181                                                      x, y,
13182                                                      wx, wy);
13183 }
13184
13185 /**
13186  * gtk_tree_view_convert_widget_to_bin_window_coords:
13187  * @tree_view: a #GtkTreeView
13188  * @wx: X coordinate relative to the widget
13189  * @wy: Y coordinate relative to the widget
13190  * @bx: return location for bin_window X coordinate
13191  * @by: return location for bin_window Y coordinate
13192  *
13193  * Converts widget coordinates to coordinates for the bin_window
13194  * (see gtk_tree_view_get_bin_window()).
13195  *
13196  * Since: 2.12
13197  **/
13198 void
13199 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13200                                                    gint         wx,
13201                                                    gint         wy,
13202                                                    gint        *bx,
13203                                                    gint        *by)
13204 {
13205   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13206
13207   if (bx)
13208     *bx = wx + tree_view->priv->hadjustment->value;
13209   if (by)
13210     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13211 }
13212
13213 /**
13214  * gtk_tree_view_convert_bin_window_to_widget_coords:
13215  * @tree_view: a #GtkTreeView
13216  * @bx: bin_window X coordinate
13217  * @by: bin_window Y coordinate
13218  * @wx: return location for widget X coordinate
13219  * @wy: return location for widget Y coordinate
13220  *
13221  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13222  * to widget relative coordinates.
13223  *
13224  * Since: 2.12
13225  **/
13226 void
13227 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13228                                                    gint         bx,
13229                                                    gint         by,
13230                                                    gint        *wx,
13231                                                    gint        *wy)
13232 {
13233   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13234
13235   if (wx)
13236     *wx = bx - tree_view->priv->hadjustment->value;
13237   if (wy)
13238     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13239 }
13240
13241 /**
13242  * gtk_tree_view_convert_tree_to_bin_window_coords:
13243  * @tree_view: a #GtkTreeView
13244  * @tx: tree X coordinate
13245  * @ty: tree Y coordinate
13246  * @bx: return location for X coordinate relative to bin_window
13247  * @by: return location for Y coordinate relative to bin_window
13248  *
13249  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13250  * to bin_window coordinates.
13251  *
13252  * Since: 2.12
13253  **/
13254 void
13255 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13256                                                  gint         tx,
13257                                                  gint         ty,
13258                                                  gint        *bx,
13259                                                  gint        *by)
13260 {
13261   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13262
13263   if (bx)
13264     *bx = tx;
13265   if (by)
13266     *by = ty - tree_view->priv->dy;
13267 }
13268
13269 /**
13270  * gtk_tree_view_convert_bin_window_to_tree_coords:
13271  * @tree_view: a #GtkTreeView
13272  * @bx: X coordinate relative to bin_window
13273  * @by: Y coordinate relative to bin_window
13274  * @tx: return location for tree X coordinate
13275  * @ty: return location for tree Y coordinate
13276  *
13277  * Converts bin_window coordinates to coordinates for the
13278  * tree (the full scrollable area of the tree).
13279  *
13280  * Since: 2.12
13281  **/
13282 void
13283 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13284                                                  gint         bx,
13285                                                  gint         by,
13286                                                  gint        *tx,
13287                                                  gint        *ty)
13288 {
13289   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13290
13291   if (tx)
13292     *tx = bx;
13293   if (ty)
13294     *ty = by + tree_view->priv->dy;
13295 }
13296
13297
13298
13299 /**
13300  * gtk_tree_view_get_visible_range:
13301  * @tree_view: A #GtkTreeView
13302  * @start_path: (allow-none): Return location for start of region, or %NULL.
13303  * @end_path: (allow-none): Return location for end of region, or %NULL.
13304  *
13305  * Sets @start_path and @end_path to be the first and last visible path.
13306  * Note that there may be invisible paths in between.
13307  *
13308  * The paths should be freed with gtk_tree_path_free() after use.
13309  *
13310  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13311  *
13312  * Since: 2.8
13313  **/
13314 gboolean
13315 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13316                                  GtkTreePath **start_path,
13317                                  GtkTreePath **end_path)
13318 {
13319   GtkRBTree *tree;
13320   GtkRBNode *node;
13321   gboolean retval;
13322   
13323   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13324
13325   if (!tree_view->priv->tree)
13326     return FALSE;
13327
13328   retval = TRUE;
13329
13330   if (start_path)
13331     {
13332       _gtk_rbtree_find_offset (tree_view->priv->tree,
13333                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13334                                &tree, &node);
13335       if (node)
13336         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13337       else
13338         retval = FALSE;
13339     }
13340
13341   if (end_path)
13342     {
13343       gint y;
13344
13345       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13346         y = tree_view->priv->height - 1;
13347       else
13348         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13349
13350       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13351       if (node)
13352         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13353       else
13354         retval = FALSE;
13355     }
13356
13357   return retval;
13358 }
13359
13360 static void
13361 unset_reorderable (GtkTreeView *tree_view)
13362 {
13363   if (tree_view->priv->reorderable)
13364     {
13365       tree_view->priv->reorderable = FALSE;
13366       g_object_notify (G_OBJECT (tree_view), "reorderable");
13367     }
13368 }
13369
13370 /**
13371  * gtk_tree_view_enable_model_drag_source:
13372  * @tree_view: a #GtkTreeView
13373  * @start_button_mask: Mask of allowed buttons to start drag
13374  * @targets: the table of targets that the drag will support
13375  * @n_targets: the number of items in @targets
13376  * @actions: the bitmask of possible actions for a drag from this
13377  *    widget
13378  *
13379  * Turns @tree_view into a drag source for automatic DND. Calling this
13380  * method sets #GtkTreeView:reorderable to %FALSE.
13381  **/
13382 void
13383 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13384                                         GdkModifierType           start_button_mask,
13385                                         const GtkTargetEntry     *targets,
13386                                         gint                      n_targets,
13387                                         GdkDragAction             actions)
13388 {
13389   TreeViewDragInfo *di;
13390
13391   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13392
13393   gtk_drag_source_set (GTK_WIDGET (tree_view),
13394                        0,
13395                        targets,
13396                        n_targets,
13397                        actions);
13398
13399   di = ensure_info (tree_view);
13400
13401   di->start_button_mask = start_button_mask;
13402   di->source_actions = actions;
13403   di->source_set = TRUE;
13404
13405   unset_reorderable (tree_view);
13406 }
13407
13408 /**
13409  * gtk_tree_view_enable_model_drag_dest:
13410  * @tree_view: a #GtkTreeView
13411  * @targets: the table of targets that the drag will support
13412  * @n_targets: the number of items in @targets
13413  * @actions: the bitmask of possible actions for a drag from this
13414  *    widget
13415  * 
13416  * Turns @tree_view into a drop destination for automatic DND. Calling
13417  * this method sets #GtkTreeView:reorderable to %FALSE.
13418  **/
13419 void
13420 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13421                                       const GtkTargetEntry     *targets,
13422                                       gint                      n_targets,
13423                                       GdkDragAction             actions)
13424 {
13425   TreeViewDragInfo *di;
13426
13427   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13428
13429   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13430                      0,
13431                      targets,
13432                      n_targets,
13433                      actions);
13434
13435   di = ensure_info (tree_view);
13436   di->dest_set = TRUE;
13437
13438   unset_reorderable (tree_view);
13439 }
13440
13441 /**
13442  * gtk_tree_view_unset_rows_drag_source:
13443  * @tree_view: a #GtkTreeView
13444  *
13445  * Undoes the effect of
13446  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13447  * #GtkTreeView:reorderable to %FALSE.
13448  **/
13449 void
13450 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13451 {
13452   TreeViewDragInfo *di;
13453
13454   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13455
13456   di = get_info (tree_view);
13457
13458   if (di)
13459     {
13460       if (di->source_set)
13461         {
13462           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13463           di->source_set = FALSE;
13464         }
13465
13466       if (!di->dest_set && !di->source_set)
13467         remove_info (tree_view);
13468     }
13469   
13470   unset_reorderable (tree_view);
13471 }
13472
13473 /**
13474  * gtk_tree_view_unset_rows_drag_dest:
13475  * @tree_view: a #GtkTreeView
13476  *
13477  * Undoes the effect of
13478  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13479  * #GtkTreeView:reorderable to %FALSE.
13480  **/
13481 void
13482 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13483 {
13484   TreeViewDragInfo *di;
13485
13486   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13487
13488   di = get_info (tree_view);
13489
13490   if (di)
13491     {
13492       if (di->dest_set)
13493         {
13494           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13495           di->dest_set = FALSE;
13496         }
13497
13498       if (!di->dest_set && !di->source_set)
13499         remove_info (tree_view);
13500     }
13501
13502   unset_reorderable (tree_view);
13503 }
13504
13505 /**
13506  * gtk_tree_view_set_drag_dest_row:
13507  * @tree_view: a #GtkTreeView
13508  * @path: (allow-none): The path of the row to highlight, or %NULL.
13509  * @pos: Specifies whether to drop before, after or into the row
13510  * 
13511  * Sets the row that is highlighted for feedback.
13512  **/
13513 void
13514 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13515                                  GtkTreePath            *path,
13516                                  GtkTreeViewDropPosition pos)
13517 {
13518   GtkTreePath *current_dest;
13519
13520   /* Note; this function is exported to allow a custom DND
13521    * implementation, so it can't touch TreeViewDragInfo
13522    */
13523
13524   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13525
13526   current_dest = NULL;
13527
13528   if (tree_view->priv->drag_dest_row)
13529     {
13530       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13531       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13532     }
13533
13534   /* special case a drop on an empty model */
13535   tree_view->priv->empty_view_drop = 0;
13536
13537   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13538       && gtk_tree_path_get_depth (path) == 1
13539       && gtk_tree_path_get_indices (path)[0] == 0)
13540     {
13541       gint n_children;
13542
13543       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13544                                                    NULL);
13545
13546       if (!n_children)
13547         tree_view->priv->empty_view_drop = 1;
13548     }
13549
13550   tree_view->priv->drag_dest_pos = pos;
13551
13552   if (path)
13553     {
13554       tree_view->priv->drag_dest_row =
13555         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13556       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13557     }
13558   else
13559     tree_view->priv->drag_dest_row = NULL;
13560
13561   if (current_dest)
13562     {
13563       GtkRBTree *tree, *new_tree;
13564       GtkRBNode *node, *new_node;
13565
13566       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13567       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13568
13569       if (tree && node)
13570         {
13571           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13572           if (new_tree && new_node)
13573             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13574
13575           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13576           if (new_tree && new_node)
13577             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13578         }
13579       gtk_tree_path_free (current_dest);
13580     }
13581 }
13582
13583 /**
13584  * gtk_tree_view_get_drag_dest_row:
13585  * @tree_view: a #GtkTreeView
13586  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13587  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13588  * 
13589  * Gets information about the row that is highlighted for feedback.
13590  **/
13591 void
13592 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13593                                  GtkTreePath             **path,
13594                                  GtkTreeViewDropPosition  *pos)
13595 {
13596   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13597
13598   if (path)
13599     {
13600       if (tree_view->priv->drag_dest_row)
13601         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13602       else
13603         {
13604           if (tree_view->priv->empty_view_drop)
13605             *path = gtk_tree_path_new_from_indices (0, -1);
13606           else
13607             *path = NULL;
13608         }
13609     }
13610
13611   if (pos)
13612     *pos = tree_view->priv->drag_dest_pos;
13613 }
13614
13615 /**
13616  * gtk_tree_view_get_dest_row_at_pos:
13617  * @tree_view: a #GtkTreeView
13618  * @drag_x: the position to determine the destination row for
13619  * @drag_y: the position to determine the destination row for
13620  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13621  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13622  * 
13623  * Determines the destination row for a given position.  @drag_x and
13624  * @drag_y are expected to be in widget coordinates.  This function is only
13625  * meaningful if @tree_view is realized.  Therefore this function will always
13626  * return %FALSE if @tree_view is not realized or does not have a model.
13627  * 
13628  * Return value: whether there is a row at the given position, %TRUE if this
13629  * is indeed the case.
13630  **/
13631 gboolean
13632 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13633                                    gint                     drag_x,
13634                                    gint                     drag_y,
13635                                    GtkTreePath            **path,
13636                                    GtkTreeViewDropPosition *pos)
13637 {
13638   gint cell_y;
13639   gint bin_x, bin_y;
13640   gdouble offset_into_row;
13641   gdouble third;
13642   GdkRectangle cell;
13643   GtkTreeViewColumn *column = NULL;
13644   GtkTreePath *tmp_path = NULL;
13645
13646   /* Note; this function is exported to allow a custom DND
13647    * implementation, so it can't touch TreeViewDragInfo
13648    */
13649
13650   g_return_val_if_fail (tree_view != NULL, FALSE);
13651   g_return_val_if_fail (drag_x >= 0, FALSE);
13652   g_return_val_if_fail (drag_y >= 0, FALSE);
13653
13654   if (path)
13655     *path = NULL;
13656
13657   if (tree_view->priv->bin_window == NULL)
13658     return FALSE;
13659
13660   if (tree_view->priv->tree == NULL)
13661     return FALSE;
13662
13663   /* If in the top third of a row, we drop before that row; if
13664    * in the bottom third, drop after that row; if in the middle,
13665    * and the row has children, drop into the row.
13666    */
13667   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13668                                                      &bin_x, &bin_y);
13669
13670   if (!gtk_tree_view_get_path_at_pos (tree_view,
13671                                       bin_x,
13672                                       bin_y,
13673                                       &tmp_path,
13674                                       &column,
13675                                       NULL,
13676                                       &cell_y))
13677     return FALSE;
13678
13679   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13680                                      &cell);
13681
13682   offset_into_row = cell_y;
13683
13684   if (path)
13685     *path = tmp_path;
13686   else
13687     gtk_tree_path_free (tmp_path);
13688
13689   tmp_path = NULL;
13690
13691   third = cell.height / 3.0;
13692
13693   if (pos)
13694     {
13695       if (offset_into_row < third)
13696         {
13697           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13698         }
13699       else if (offset_into_row < (cell.height / 2.0))
13700         {
13701           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13702         }
13703       else if (offset_into_row < third * 2.0)
13704         {
13705           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13706         }
13707       else
13708         {
13709           *pos = GTK_TREE_VIEW_DROP_AFTER;
13710         }
13711     }
13712
13713   return TRUE;
13714 }
13715
13716
13717
13718 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13719 /**
13720  * gtk_tree_view_create_row_drag_icon:
13721  * @tree_view: a #GtkTreeView
13722  * @path: a #GtkTreePath in @tree_view
13723  *
13724  * Creates a #cairo_surface_t representation of the row at @path.  
13725  * This image is used for a drag icon.
13726  *
13727  * Return value: (transfer full): a newly-allocated surface of the drag icon.
13728  **/
13729 cairo_surface_t *
13730 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13731                                     GtkTreePath  *path)
13732 {
13733   GtkTreeIter   iter;
13734   GtkRBTree    *tree;
13735   GtkRBNode    *node;
13736   GtkStyle *style;
13737   gint cell_offset;
13738   GList *list;
13739   GdkRectangle background_area;
13740   GtkWidget *widget;
13741   gint depth;
13742   /* start drawing inside the black outline */
13743   gint x = 1, y = 1;
13744   cairo_surface_t *surface;
13745   gint bin_window_width;
13746   gboolean is_separator = FALSE;
13747   gboolean rtl;
13748   cairo_t *cr;
13749
13750   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13751   g_return_val_if_fail (path != NULL, NULL);
13752
13753   widget = GTK_WIDGET (tree_view);
13754
13755   if (!gtk_widget_get_realized (widget))
13756     return NULL;
13757
13758   depth = gtk_tree_path_get_depth (path);
13759
13760   _gtk_tree_view_find_node (tree_view,
13761                             path,
13762                             &tree,
13763                             &node);
13764
13765   if (tree == NULL)
13766     return NULL;
13767
13768   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13769                                 &iter,
13770                                 path))
13771     return NULL;
13772
13773   style = gtk_widget_get_style (widget);
13774
13775   is_separator = row_is_separator (tree_view, &iter, NULL);
13776
13777   cell_offset = x;
13778
13779   background_area.y = y;
13780   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13781
13782   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
13783
13784   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
13785                                                CAIRO_CONTENT_COLOR,
13786                                                bin_window_width + 2,
13787                                                background_area.height + 2);
13788
13789   cr = cairo_create (surface);
13790   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13791   cairo_paint (cr);
13792
13793   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13794
13795   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13796       list;
13797       list = (rtl ? list->prev : list->next))
13798     {
13799       GtkTreeViewColumn *column = list->data;
13800       GdkRectangle cell_area;
13801       gint vertical_separator;
13802
13803       if (!column->visible)
13804         continue;
13805
13806       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13807                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13808                                                node->children?TRUE:FALSE);
13809
13810       background_area.x = cell_offset;
13811       background_area.width = column->width;
13812
13813       gtk_widget_style_get (widget,
13814                             "vertical-separator", &vertical_separator,
13815                             NULL);
13816
13817       cell_area = background_area;
13818
13819       cell_area.y += vertical_separator / 2;
13820       cell_area.height -= vertical_separator;
13821
13822       if (gtk_tree_view_is_expander_column (tree_view, column))
13823         {
13824           if (!rtl)
13825             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13826           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13827
13828           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13829             {
13830               if (!rtl)
13831                 cell_area.x += depth * tree_view->priv->expander_size;
13832               cell_area.width -= depth * tree_view->priv->expander_size;
13833             }
13834         }
13835
13836       if (gtk_tree_view_column_cell_is_visible (column))
13837         {
13838           if (is_separator)
13839             gtk_paint_hline (style,
13840                                    cr,
13841                                    GTK_STATE_NORMAL,
13842                                    widget,
13843                                    NULL,
13844                                    cell_area.x,
13845                                    cell_area.x + cell_area.width,
13846                                    cell_area.y + cell_area.height / 2);
13847           else
13848             _gtk_tree_view_column_cell_render (column,
13849                                                cr,
13850                                                &background_area,
13851                                                &cell_area,
13852                                                0);
13853         }
13854       cell_offset += column->width;
13855     }
13856
13857   cairo_set_source_rgb (cr, 0, 0, 0);
13858   cairo_rectangle (cr, 
13859                    0.5, 0.5, 
13860                    bin_window_width + 1,
13861                    background_area.height + 1);
13862   cairo_set_line_width (cr, 1.0);
13863   cairo_stroke (cr);
13864
13865   cairo_destroy (cr);
13866
13867   cairo_surface_set_device_offset (surface, 2, 2);
13868
13869   return surface;
13870 }
13871
13872
13873 /**
13874  * gtk_tree_view_set_destroy_count_func:
13875  * @tree_view: A #GtkTreeView
13876  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13877  * @data: (allow-none): User data to be passed to @func, or %NULL
13878  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13879  *
13880  * This function should almost never be used.  It is meant for private use by
13881  * ATK for determining the number of visible children that are removed when the
13882  * user collapses a row, or a row is deleted.
13883  **/
13884 void
13885 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13886                                       GtkTreeDestroyCountFunc  func,
13887                                       gpointer                 data,
13888                                       GDestroyNotify           destroy)
13889 {
13890   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13891
13892   if (tree_view->priv->destroy_count_destroy)
13893     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13894
13895   tree_view->priv->destroy_count_func = func;
13896   tree_view->priv->destroy_count_data = data;
13897   tree_view->priv->destroy_count_destroy = destroy;
13898 }
13899
13900
13901 /*
13902  * Interactive search
13903  */
13904
13905 /**
13906  * gtk_tree_view_set_enable_search:
13907  * @tree_view: A #GtkTreeView
13908  * @enable_search: %TRUE, if the user can search interactively
13909  *
13910  * If @enable_search is set, then the user can type in text to search through
13911  * the tree interactively (this is sometimes called "typeahead find").
13912  * 
13913  * Note that even if this is %FALSE, the user can still initiate a search 
13914  * using the "start-interactive-search" key binding.
13915  */
13916 void
13917 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13918                                  gboolean     enable_search)
13919 {
13920   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13921
13922   enable_search = !!enable_search;
13923   
13924   if (tree_view->priv->enable_search != enable_search)
13925     {
13926        tree_view->priv->enable_search = enable_search;
13927        g_object_notify (G_OBJECT (tree_view), "enable-search");
13928     }
13929 }
13930
13931 /**
13932  * gtk_tree_view_get_enable_search:
13933  * @tree_view: A #GtkTreeView
13934  *
13935  * Returns whether or not the tree allows to start interactive searching 
13936  * by typing in text.
13937  *
13938  * Return value: whether or not to let the user search interactively
13939  */
13940 gboolean
13941 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13942 {
13943   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13944
13945   return tree_view->priv->enable_search;
13946 }
13947
13948
13949 /**
13950  * gtk_tree_view_get_search_column:
13951  * @tree_view: A #GtkTreeView
13952  *
13953  * Gets the column searched on by the interactive search code.
13954  *
13955  * Return value: the column the interactive search code searches in.
13956  */
13957 gint
13958 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13959 {
13960   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13961
13962   return (tree_view->priv->search_column);
13963 }
13964
13965 /**
13966  * gtk_tree_view_set_search_column:
13967  * @tree_view: A #GtkTreeView
13968  * @column: the column of the model to search in, or -1 to disable searching
13969  *
13970  * Sets @column as the column where the interactive search code should
13971  * search in for the current model. 
13972  * 
13973  * If the search column is set, users can use the "start-interactive-search"
13974  * key binding to bring up search popup. The enable-search property controls
13975  * whether simply typing text will also start an interactive search.
13976  *
13977  * Note that @column refers to a column of the current model. The search 
13978  * column is reset to -1 when the model is changed.
13979  */
13980 void
13981 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13982                                  gint         column)
13983 {
13984   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13985   g_return_if_fail (column >= -1);
13986
13987   if (tree_view->priv->search_column == column)
13988     return;
13989
13990   tree_view->priv->search_column = column;
13991   g_object_notify (G_OBJECT (tree_view), "search-column");
13992 }
13993
13994 /**
13995  * gtk_tree_view_get_search_equal_func:
13996  * @tree_view: A #GtkTreeView
13997  *
13998  * Returns the compare function currently in use.
13999  *
14000  * Return value: the currently used compare function for the search code.
14001  */
14002
14003 GtkTreeViewSearchEqualFunc
14004 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14005 {
14006   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14007
14008   return tree_view->priv->search_equal_func;
14009 }
14010
14011 /**
14012  * gtk_tree_view_set_search_equal_func:
14013  * @tree_view: A #GtkTreeView
14014  * @search_equal_func: the compare function to use during the search
14015  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14016  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14017  *
14018  * Sets the compare function for the interactive search capabilities; note
14019  * that somewhat like strcmp() returning 0 for equality
14020  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14021  **/
14022 void
14023 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14024                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14025                                      gpointer                    search_user_data,
14026                                      GDestroyNotify              search_destroy)
14027 {
14028   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14029   g_return_if_fail (search_equal_func != NULL);
14030
14031   if (tree_view->priv->search_destroy)
14032     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14033
14034   tree_view->priv->search_equal_func = search_equal_func;
14035   tree_view->priv->search_user_data = search_user_data;
14036   tree_view->priv->search_destroy = search_destroy;
14037   if (tree_view->priv->search_equal_func == NULL)
14038     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14039 }
14040
14041 /**
14042  * gtk_tree_view_get_search_entry:
14043  * @tree_view: A #GtkTreeView
14044  *
14045  * Returns the #GtkEntry which is currently in use as interactive search
14046  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14047  * will be returned.
14048  *
14049  * Return value: (transfer none): the entry currently in use as search entry.
14050  *
14051  * Since: 2.10
14052  */
14053 GtkEntry *
14054 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14055 {
14056   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14057
14058   if (tree_view->priv->search_custom_entry_set)
14059     return GTK_ENTRY (tree_view->priv->search_entry);
14060
14061   return NULL;
14062 }
14063
14064 /**
14065  * gtk_tree_view_set_search_entry:
14066  * @tree_view: A #GtkTreeView
14067  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14068  *
14069  * Sets the entry which the interactive search code will use for this
14070  * @tree_view.  This is useful when you want to provide a search entry
14071  * in our interface at all time at a fixed position.  Passing %NULL for
14072  * @entry will make the interactive search code use the built-in popup
14073  * entry again.
14074  *
14075  * Since: 2.10
14076  */
14077 void
14078 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14079                                 GtkEntry    *entry)
14080 {
14081   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14082   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14083
14084   if (tree_view->priv->search_custom_entry_set)
14085     {
14086       if (tree_view->priv->search_entry_changed_id)
14087         {
14088           g_signal_handler_disconnect (tree_view->priv->search_entry,
14089                                        tree_view->priv->search_entry_changed_id);
14090           tree_view->priv->search_entry_changed_id = 0;
14091         }
14092       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14093                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14094                                             tree_view);
14095
14096       g_object_unref (tree_view->priv->search_entry);
14097     }
14098   else if (tree_view->priv->search_window)
14099     {
14100       gtk_widget_destroy (tree_view->priv->search_window);
14101
14102       tree_view->priv->search_window = NULL;
14103     }
14104
14105   if (entry)
14106     {
14107       tree_view->priv->search_entry = g_object_ref (entry);
14108       tree_view->priv->search_custom_entry_set = TRUE;
14109
14110       if (tree_view->priv->search_entry_changed_id == 0)
14111         {
14112           tree_view->priv->search_entry_changed_id =
14113             g_signal_connect (tree_view->priv->search_entry, "changed",
14114                               G_CALLBACK (gtk_tree_view_search_init),
14115                               tree_view);
14116         }
14117       
14118         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14119                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14120                           tree_view);
14121
14122         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14123     }
14124   else
14125     {
14126       tree_view->priv->search_entry = NULL;
14127       tree_view->priv->search_custom_entry_set = FALSE;
14128     }
14129 }
14130
14131 /**
14132  * gtk_tree_view_set_search_position_func:
14133  * @tree_view: A #GtkTreeView
14134  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14135  *    to use the default search position function
14136  * @data: (allow-none): user data to pass to @func, or %NULL
14137  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14138  *
14139  * Sets the function to use when positioning the search dialog.
14140  *
14141  * Since: 2.10
14142  **/
14143 void
14144 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14145                                         GtkTreeViewSearchPositionFunc  func,
14146                                         gpointer                       user_data,
14147                                         GDestroyNotify                 destroy)
14148 {
14149   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14150
14151   if (tree_view->priv->search_position_destroy)
14152     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14153
14154   tree_view->priv->search_position_func = func;
14155   tree_view->priv->search_position_user_data = user_data;
14156   tree_view->priv->search_position_destroy = destroy;
14157   if (tree_view->priv->search_position_func == NULL)
14158     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14159 }
14160
14161 /**
14162  * gtk_tree_view_get_search_position_func:
14163  * @tree_view: A #GtkTreeView
14164  *
14165  * Returns the positioning function currently in use.
14166  *
14167  * Return value: the currently used function for positioning the search dialog.
14168  *
14169  * Since: 2.10
14170  */
14171 GtkTreeViewSearchPositionFunc
14172 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14173 {
14174   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14175
14176   return tree_view->priv->search_position_func;
14177 }
14178
14179
14180 static void
14181 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14182                                   GtkTreeView *tree_view,
14183                                   GdkDevice   *device)
14184 {
14185   if (tree_view->priv->disable_popdown)
14186     return;
14187
14188   if (tree_view->priv->search_entry_changed_id)
14189     {
14190       g_signal_handler_disconnect (tree_view->priv->search_entry,
14191                                    tree_view->priv->search_entry_changed_id);
14192       tree_view->priv->search_entry_changed_id = 0;
14193     }
14194   if (tree_view->priv->typeselect_flush_timeout)
14195     {
14196       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14197       tree_view->priv->typeselect_flush_timeout = 0;
14198     }
14199         
14200   if (gtk_widget_get_visible (search_dialog))
14201     {
14202       /* send focus-in event */
14203       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14204       gtk_widget_hide (search_dialog);
14205       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14206       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14207     }
14208 }
14209
14210 static void
14211 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14212                                     GtkWidget   *search_dialog,
14213                                     gpointer     user_data)
14214 {
14215   gint x, y;
14216   gint tree_x, tree_y;
14217   gint tree_width, tree_height;
14218   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14219   GdkScreen *screen = gdk_window_get_screen (tree_window);
14220   GtkRequisition requisition;
14221   gint monitor_num;
14222   GdkRectangle monitor;
14223
14224   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14225   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14226
14227   gtk_widget_realize (search_dialog);
14228
14229   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14230   tree_width = gdk_window_get_width (tree_window);
14231   tree_height = gdk_window_get_height (tree_window);
14232   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14233
14234   if (tree_x + tree_width > gdk_screen_get_width (screen))
14235     x = gdk_screen_get_width (screen) - requisition.width;
14236   else if (tree_x + tree_width - requisition.width < 0)
14237     x = 0;
14238   else
14239     x = tree_x + tree_width - requisition.width;
14240
14241   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14242     y = gdk_screen_get_height (screen) - requisition.height;
14243   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14244     y = 0;
14245   else
14246     y = tree_y + tree_height;
14247
14248   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14249 }
14250
14251 static void
14252 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14253                                       GtkMenu  *menu,
14254                                       gpointer  data)
14255 {
14256   GtkTreeView *tree_view = (GtkTreeView *)data;
14257
14258   tree_view->priv->disable_popdown = 1;
14259   g_signal_connect (menu, "hide",
14260                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14261 }
14262
14263 /* Because we're visible but offscreen, we just set a flag in the preedit
14264  * callback.
14265  */
14266 static void
14267 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14268                                       GtkTreeView  *tree_view)
14269 {
14270   tree_view->priv->imcontext_changed = 1;
14271   if (tree_view->priv->typeselect_flush_timeout)
14272     {
14273       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14274       tree_view->priv->typeselect_flush_timeout =
14275         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14276                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14277                        tree_view);
14278     }
14279
14280 }
14281
14282 static void
14283 gtk_tree_view_search_activate (GtkEntry    *entry,
14284                                GtkTreeView *tree_view)
14285 {
14286   GtkTreePath *path;
14287   GtkRBNode *node;
14288   GtkRBTree *tree;
14289
14290   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14291                                     tree_view,
14292                                     gtk_get_current_event_device ());
14293
14294   /* If we have a row selected and it's the cursor row, we activate
14295    * the row XXX */
14296   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14297     {
14298       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14299       
14300       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14301       
14302       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14303         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14304       
14305       gtk_tree_path_free (path);
14306     }
14307 }
14308
14309 static gboolean
14310 gtk_tree_view_real_search_enable_popdown (gpointer data)
14311 {
14312   GtkTreeView *tree_view = (GtkTreeView *)data;
14313
14314   tree_view->priv->disable_popdown = 0;
14315
14316   return FALSE;
14317 }
14318
14319 static void
14320 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14321                                      gpointer   data)
14322 {
14323   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14324 }
14325
14326 static gboolean
14327 gtk_tree_view_search_delete_event (GtkWidget *widget,
14328                                    GdkEventAny *event,
14329                                    GtkTreeView *tree_view)
14330 {
14331   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14332
14333   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14334
14335   return TRUE;
14336 }
14337
14338 static gboolean
14339 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14340                                          GdkEventButton *event,
14341                                          GtkTreeView *tree_view)
14342 {
14343   GdkDevice *keyb_device;
14344
14345   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14346
14347   keyb_device = gdk_device_get_associated_device (event->device);
14348   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14349
14350   if (event->window == tree_view->priv->bin_window)
14351     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14352
14353   return TRUE;
14354 }
14355
14356 static gboolean
14357 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14358                                    GdkEventScroll *event,
14359                                    GtkTreeView *tree_view)
14360 {
14361   gboolean retval = FALSE;
14362
14363   if (event->direction == GDK_SCROLL_UP)
14364     {
14365       gtk_tree_view_search_move (widget, tree_view, TRUE);
14366       retval = TRUE;
14367     }
14368   else if (event->direction == GDK_SCROLL_DOWN)
14369     {
14370       gtk_tree_view_search_move (widget, tree_view, FALSE);
14371       retval = TRUE;
14372     }
14373
14374   /* renew the flush timeout */
14375   if (retval && tree_view->priv->typeselect_flush_timeout
14376       && !tree_view->priv->search_custom_entry_set)
14377     {
14378       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14379       tree_view->priv->typeselect_flush_timeout =
14380         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14381                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14382                        tree_view);
14383     }
14384
14385   return retval;
14386 }
14387
14388 static gboolean
14389 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14390                                       GdkEventKey *event,
14391                                       GtkTreeView *tree_view)
14392 {
14393   gboolean retval = FALSE;
14394
14395   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14396   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14397
14398   /* close window and cancel the search */
14399   if (!tree_view->priv->search_custom_entry_set
14400       && (event->keyval == GDK_KEY_Escape ||
14401           event->keyval == GDK_KEY_Tab ||
14402             event->keyval == GDK_KEY_KP_Tab ||
14403             event->keyval == GDK_KEY_ISO_Left_Tab))
14404     {
14405       gtk_tree_view_search_dialog_hide (widget, tree_view,
14406                                         gdk_event_get_device ((GdkEvent *) event));
14407       return TRUE;
14408     }
14409
14410   /* select previous matching iter */
14411   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14412     {
14413       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14414         gtk_widget_error_bell (widget);
14415
14416       retval = TRUE;
14417     }
14418
14419   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14420       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14421     {
14422       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14423         gtk_widget_error_bell (widget);
14424
14425       retval = TRUE;
14426     }
14427
14428   /* select next matching iter */
14429   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14430     {
14431       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14432         gtk_widget_error_bell (widget);
14433
14434       retval = TRUE;
14435     }
14436
14437   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14438       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14439     {
14440       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14441         gtk_widget_error_bell (widget);
14442
14443       retval = TRUE;
14444     }
14445
14446   /* renew the flush timeout */
14447   if (retval && tree_view->priv->typeselect_flush_timeout
14448       && !tree_view->priv->search_custom_entry_set)
14449     {
14450       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14451       tree_view->priv->typeselect_flush_timeout =
14452         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14453                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14454                        tree_view);
14455     }
14456
14457   return retval;
14458 }
14459
14460 /*  this function returns FALSE if there is a search string but
14461  *  nothing was found, and TRUE otherwise.
14462  */
14463 static gboolean
14464 gtk_tree_view_search_move (GtkWidget   *window,
14465                            GtkTreeView *tree_view,
14466                            gboolean     up)
14467 {
14468   gboolean ret;
14469   gint len;
14470   gint count = 0;
14471   const gchar *text;
14472   GtkTreeIter iter;
14473   GtkTreeModel *model;
14474   GtkTreeSelection *selection;
14475
14476   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14477
14478   g_return_val_if_fail (text != NULL, FALSE);
14479
14480   len = strlen (text);
14481
14482   if (up && tree_view->priv->selected_iter == 1)
14483     return strlen (text) < 1;
14484
14485   len = strlen (text);
14486
14487   if (len < 1)
14488     return TRUE;
14489
14490   model = gtk_tree_view_get_model (tree_view);
14491   selection = gtk_tree_view_get_selection (tree_view);
14492
14493   /* search */
14494   gtk_tree_selection_unselect_all (selection);
14495   if (!gtk_tree_model_get_iter_first (model, &iter))
14496     return TRUE;
14497
14498   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14499                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14500
14501   if (ret)
14502     {
14503       /* found */
14504       tree_view->priv->selected_iter += up?(-1):(1);
14505       return TRUE;
14506     }
14507   else
14508     {
14509       /* return to old iter */
14510       count = 0;
14511       gtk_tree_model_get_iter_first (model, &iter);
14512       gtk_tree_view_search_iter (model, selection,
14513                                  &iter, text,
14514                                  &count, tree_view->priv->selected_iter);
14515       return FALSE;
14516     }
14517 }
14518
14519 static gboolean
14520 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14521                                  gint          column,
14522                                  const gchar  *key,
14523                                  GtkTreeIter  *iter,
14524                                  gpointer      search_data)
14525 {
14526   gboolean retval = TRUE;
14527   const gchar *str;
14528   gchar *normalized_string;
14529   gchar *normalized_key;
14530   gchar *case_normalized_string = NULL;
14531   gchar *case_normalized_key = NULL;
14532   GValue value = {0,};
14533   GValue transformed = {0,};
14534
14535   gtk_tree_model_get_value (model, iter, column, &value);
14536
14537   g_value_init (&transformed, G_TYPE_STRING);
14538
14539   if (!g_value_transform (&value, &transformed))
14540     {
14541       g_value_unset (&value);
14542       return TRUE;
14543     }
14544
14545   g_value_unset (&value);
14546
14547   str = g_value_get_string (&transformed);
14548   if (!str)
14549     {
14550       g_value_unset (&transformed);
14551       return TRUE;
14552     }
14553
14554   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14555   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14556
14557   if (normalized_string && normalized_key)
14558     {
14559       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14560       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14561
14562       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14563         retval = FALSE;
14564     }
14565
14566   g_value_unset (&transformed);
14567   g_free (normalized_key);
14568   g_free (normalized_string);
14569   g_free (case_normalized_key);
14570   g_free (case_normalized_string);
14571
14572   return retval;
14573 }
14574
14575 static gboolean
14576 gtk_tree_view_search_iter (GtkTreeModel     *model,
14577                            GtkTreeSelection *selection,
14578                            GtkTreeIter      *iter,
14579                            const gchar      *text,
14580                            gint             *count,
14581                            gint              n)
14582 {
14583   GtkRBTree *tree = NULL;
14584   GtkRBNode *node = NULL;
14585   GtkTreePath *path;
14586
14587   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14588
14589   path = gtk_tree_model_get_path (model, iter);
14590   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14591
14592   do
14593     {
14594       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14595         {
14596           (*count)++;
14597           if (*count == n)
14598             {
14599               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14600                                             TRUE, 0.5, 0.0);
14601               gtk_tree_selection_select_iter (selection, iter);
14602               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14603
14604               if (path)
14605                 gtk_tree_path_free (path);
14606
14607               return TRUE;
14608             }
14609         }
14610
14611       if (node->children)
14612         {
14613           gboolean has_child;
14614           GtkTreeIter tmp;
14615
14616           tree = node->children;
14617           node = tree->root;
14618
14619           while (node->left != tree->nil)
14620             node = node->left;
14621
14622           tmp = *iter;
14623           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14624           gtk_tree_path_down (path);
14625
14626           /* sanity check */
14627           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14628         }
14629       else
14630         {
14631           gboolean done = FALSE;
14632
14633           do
14634             {
14635               node = _gtk_rbtree_next (tree, node);
14636
14637               if (node)
14638                 {
14639                   gboolean has_next;
14640
14641                   has_next = gtk_tree_model_iter_next (model, iter);
14642
14643                   done = TRUE;
14644                   gtk_tree_path_next (path);
14645
14646                   /* sanity check */
14647                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14648                 }
14649               else
14650                 {
14651                   gboolean has_parent;
14652                   GtkTreeIter tmp_iter = *iter;
14653
14654                   node = tree->parent_node;
14655                   tree = tree->parent_tree;
14656
14657                   if (!tree)
14658                     {
14659                       if (path)
14660                         gtk_tree_path_free (path);
14661
14662                       /* we've run out of tree, done with this func */
14663                       return FALSE;
14664                     }
14665
14666                   has_parent = gtk_tree_model_iter_parent (model,
14667                                                            iter,
14668                                                            &tmp_iter);
14669                   gtk_tree_path_up (path);
14670
14671                   /* sanity check */
14672                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14673                 }
14674             }
14675           while (!done);
14676         }
14677     }
14678   while (1);
14679
14680   return FALSE;
14681 }
14682
14683 static void
14684 gtk_tree_view_search_init (GtkWidget   *entry,
14685                            GtkTreeView *tree_view)
14686 {
14687   gint ret;
14688   gint count = 0;
14689   const gchar *text;
14690   GtkTreeIter iter;
14691   GtkTreeModel *model;
14692   GtkTreeSelection *selection;
14693
14694   g_return_if_fail (GTK_IS_ENTRY (entry));
14695   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14696
14697   text = gtk_entry_get_text (GTK_ENTRY (entry));
14698
14699   model = gtk_tree_view_get_model (tree_view);
14700   selection = gtk_tree_view_get_selection (tree_view);
14701
14702   /* search */
14703   gtk_tree_selection_unselect_all (selection);
14704   if (tree_view->priv->typeselect_flush_timeout
14705       && !tree_view->priv->search_custom_entry_set)
14706     {
14707       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14708       tree_view->priv->typeselect_flush_timeout =
14709         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14710                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14711                        tree_view);
14712     }
14713
14714   if (*text == '\0')
14715     return;
14716
14717   if (!gtk_tree_model_get_iter_first (model, &iter))
14718     return;
14719
14720   ret = gtk_tree_view_search_iter (model, selection,
14721                                    &iter, text,
14722                                    &count, 1);
14723
14724   if (ret)
14725     tree_view->priv->selected_iter = 1;
14726 }
14727
14728 static void
14729 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14730                              GtkTreeView     *tree_view)
14731 {
14732   if (tree_view->priv->edited_column == NULL)
14733     return;
14734
14735   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14736   tree_view->priv->edited_column = NULL;
14737
14738   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14739     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14740
14741   g_signal_handlers_disconnect_by_func (cell_editable,
14742                                         gtk_tree_view_remove_widget,
14743                                         tree_view);
14744
14745   gtk_container_remove (GTK_CONTAINER (tree_view),
14746                         GTK_WIDGET (cell_editable));  
14747
14748   /* FIXME should only redraw a single node */
14749   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14750 }
14751
14752 static gboolean
14753 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14754                              GtkTreePath *cursor_path)
14755 {
14756   GtkTreeIter iter;
14757   GdkRectangle background_area;
14758   GdkRectangle cell_area;
14759   GtkCellEditable *editable_widget = NULL;
14760   gchar *path_string;
14761   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14762   gint retval = FALSE;
14763   GtkRBTree *cursor_tree;
14764   GtkRBNode *cursor_node;
14765
14766   g_assert (tree_view->priv->focus_column);
14767
14768   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14769     return FALSE;
14770
14771   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14772       cursor_node == NULL)
14773     return FALSE;
14774
14775   path_string = gtk_tree_path_to_string (cursor_path);
14776   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14777
14778   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14779
14780   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14781                                            tree_view->priv->model,
14782                                            &iter,
14783                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14784                                            cursor_node->children?TRUE:FALSE);
14785   gtk_tree_view_get_background_area (tree_view,
14786                                      cursor_path,
14787                                      tree_view->priv->focus_column,
14788                                      &background_area);
14789   gtk_tree_view_get_cell_area (tree_view,
14790                                cursor_path,
14791                                tree_view->priv->focus_column,
14792                                &cell_area);
14793
14794   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14795                                         &editable_widget,
14796                                         NULL,
14797                                         path_string,
14798                                         &background_area,
14799                                         &cell_area,
14800                                         flags))
14801     {
14802       retval = TRUE;
14803       if (editable_widget != NULL)
14804         {
14805           gint left, right;
14806           GdkRectangle area;
14807           GtkCellRenderer *cell;
14808
14809           area = cell_area;
14810           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14811
14812           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14813
14814           area.x += left;
14815           area.width -= right + left;
14816
14817           gtk_tree_view_real_start_editing (tree_view,
14818                                             tree_view->priv->focus_column,
14819                                             cursor_path,
14820                                             editable_widget,
14821                                             &area,
14822                                             NULL,
14823                                             flags);
14824         }
14825
14826     }
14827   g_free (path_string);
14828   return retval;
14829 }
14830
14831 static void
14832 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14833                                   GtkTreeViewColumn *column,
14834                                   GtkTreePath       *path,
14835                                   GtkCellEditable   *cell_editable,
14836                                   GdkRectangle      *cell_area,
14837                                   GdkEvent          *event,
14838                                   guint              flags)
14839 {
14840   gint pre_val = tree_view->priv->vadjustment->value;
14841   GtkRequisition requisition;
14842
14843   tree_view->priv->edited_column = column;
14844   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14845
14846   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14847   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14848
14849   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
14850                                  &requisition, NULL);
14851
14852   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14853
14854   if (requisition.height < cell_area->height)
14855     {
14856       gint diff = cell_area->height - requisition.height;
14857       gtk_tree_view_put (tree_view,
14858                          GTK_WIDGET (cell_editable),
14859                          cell_area->x, cell_area->y + diff/2,
14860                          cell_area->width, requisition.height);
14861     }
14862   else
14863     {
14864       gtk_tree_view_put (tree_view,
14865                          GTK_WIDGET (cell_editable),
14866                          cell_area->x, cell_area->y,
14867                          cell_area->width, cell_area->height);
14868     }
14869
14870   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14871                                    (GdkEvent *)event);
14872
14873   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14874   g_signal_connect (cell_editable, "remove-widget",
14875                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14876 }
14877
14878 static void
14879 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14880                             gboolean     cancel_editing)
14881 {
14882   GtkTreeViewColumn *column;
14883   GtkCellRenderer *cell;
14884
14885   if (tree_view->priv->edited_column == NULL)
14886     return;
14887
14888   /*
14889    * This is very evil. We need to do this, because
14890    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14891    * later on. If gtk_tree_view_row_changed notices
14892    * tree_view->priv->edited_column != NULL, it'll call
14893    * gtk_tree_view_stop_editing again. Bad things will happen then.
14894    *
14895    * Please read that again if you intend to modify anything here.
14896    */
14897
14898   column = tree_view->priv->edited_column;
14899   tree_view->priv->edited_column = NULL;
14900
14901   cell = _gtk_tree_view_column_get_edited_cell (column);
14902   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14903
14904   if (!cancel_editing)
14905     gtk_cell_editable_editing_done (column->editable_widget);
14906
14907   tree_view->priv->edited_column = column;
14908
14909   gtk_cell_editable_remove_widget (column->editable_widget);
14910 }
14911
14912
14913 /**
14914  * gtk_tree_view_set_hover_selection:
14915  * @tree_view: a #GtkTreeView
14916  * @hover: %TRUE to enable hover selection mode
14917  *
14918  * Enables of disables the hover selection mode of @tree_view.
14919  * Hover selection makes the selected row follow the pointer.
14920  * Currently, this works only for the selection modes 
14921  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14922  * 
14923  * Since: 2.6
14924  **/
14925 void     
14926 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14927                                    gboolean     hover)
14928 {
14929   hover = hover != FALSE;
14930
14931   if (hover != tree_view->priv->hover_selection)
14932     {
14933       tree_view->priv->hover_selection = hover;
14934
14935       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14936     }
14937 }
14938
14939 /**
14940  * gtk_tree_view_get_hover_selection:
14941  * @tree_view: a #GtkTreeView
14942  * 
14943  * Returns whether hover selection mode is turned on for @tree_view.
14944  * 
14945  * Return value: %TRUE if @tree_view is in hover selection mode
14946  *
14947  * Since: 2.6 
14948  **/
14949 gboolean 
14950 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14951 {
14952   return tree_view->priv->hover_selection;
14953 }
14954
14955 /**
14956  * gtk_tree_view_set_hover_expand:
14957  * @tree_view: a #GtkTreeView
14958  * @expand: %TRUE to enable hover selection mode
14959  *
14960  * Enables of disables the hover expansion mode of @tree_view.
14961  * Hover expansion makes rows expand or collapse if the pointer 
14962  * moves over them.
14963  * 
14964  * Since: 2.6
14965  **/
14966 void     
14967 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14968                                 gboolean     expand)
14969 {
14970   expand = expand != FALSE;
14971
14972   if (expand != tree_view->priv->hover_expand)
14973     {
14974       tree_view->priv->hover_expand = expand;
14975
14976       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14977     }
14978 }
14979
14980 /**
14981  * gtk_tree_view_get_hover_expand:
14982  * @tree_view: a #GtkTreeView
14983  * 
14984  * Returns whether hover expansion mode is turned on for @tree_view.
14985  * 
14986  * Return value: %TRUE if @tree_view is in hover expansion mode
14987  *
14988  * Since: 2.6 
14989  **/
14990 gboolean 
14991 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14992 {
14993   return tree_view->priv->hover_expand;
14994 }
14995
14996 /**
14997  * gtk_tree_view_set_rubber_banding:
14998  * @tree_view: a #GtkTreeView
14999  * @enable: %TRUE to enable rubber banding
15000  *
15001  * Enables or disables rubber banding in @tree_view.  If the selection mode
15002  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15003  * multiple rows by dragging the mouse.
15004  * 
15005  * Since: 2.10
15006  **/
15007 void
15008 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15009                                   gboolean     enable)
15010 {
15011   enable = enable != FALSE;
15012
15013   if (enable != tree_view->priv->rubber_banding_enable)
15014     {
15015       tree_view->priv->rubber_banding_enable = enable;
15016
15017       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15018     }
15019 }
15020
15021 /**
15022  * gtk_tree_view_get_rubber_banding:
15023  * @tree_view: a #GtkTreeView
15024  * 
15025  * Returns whether rubber banding is turned on for @tree_view.  If the
15026  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15027  * user to select multiple rows by dragging the mouse.
15028  * 
15029  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15030  *
15031  * Since: 2.10
15032  **/
15033 gboolean
15034 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15035 {
15036   return tree_view->priv->rubber_banding_enable;
15037 }
15038
15039 /**
15040  * gtk_tree_view_is_rubber_banding_active:
15041  * @tree_view: a #GtkTreeView
15042  * 
15043  * Returns whether a rubber banding operation is currently being done
15044  * in @tree_view.
15045  *
15046  * Return value: %TRUE if a rubber banding operation is currently being
15047  * done in @tree_view.
15048  *
15049  * Since: 2.12
15050  **/
15051 gboolean
15052 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15053 {
15054   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15055
15056   if (tree_view->priv->rubber_banding_enable
15057       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15058     return TRUE;
15059
15060   return FALSE;
15061 }
15062
15063 /**
15064  * gtk_tree_view_get_row_separator_func:
15065  * @tree_view: a #GtkTreeView
15066  * 
15067  * Returns the current row separator function.
15068  * 
15069  * Return value: the current row separator function.
15070  *
15071  * Since: 2.6
15072  **/
15073 GtkTreeViewRowSeparatorFunc 
15074 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15075 {
15076   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15077
15078   return tree_view->priv->row_separator_func;
15079 }
15080
15081 /**
15082  * gtk_tree_view_set_row_separator_func:
15083  * @tree_view: a #GtkTreeView
15084  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15085  * @data: (allow-none): user data to pass to @func, or %NULL
15086  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15087  * 
15088  * Sets the row separator function, which is used to determine
15089  * whether a row should be drawn as a separator. If the row separator
15090  * function is %NULL, no separators are drawn. This is the default value.
15091  *
15092  * Since: 2.6
15093  **/
15094 void
15095 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15096                                       GtkTreeViewRowSeparatorFunc  func,
15097                                       gpointer                     data,
15098                                       GDestroyNotify               destroy)
15099 {
15100   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15101
15102   if (tree_view->priv->row_separator_destroy)
15103     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15104
15105   tree_view->priv->row_separator_func = func;
15106   tree_view->priv->row_separator_data = data;
15107   tree_view->priv->row_separator_destroy = destroy;
15108
15109   /* Have the tree recalculate heights */
15110   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15111   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15112 }
15113
15114   
15115 static void
15116 gtk_tree_view_grab_notify (GtkWidget *widget,
15117                            gboolean   was_grabbed)
15118 {
15119   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15120
15121   tree_view->priv->in_grab = !was_grabbed;
15122
15123   if (!was_grabbed)
15124     {
15125       tree_view->priv->pressed_button = -1;
15126
15127       if (tree_view->priv->rubber_band_status)
15128         gtk_tree_view_stop_rubber_band (tree_view);
15129     }
15130 }
15131
15132 static void
15133 gtk_tree_view_state_changed (GtkWidget      *widget,
15134                              GtkStateType    previous_state)
15135 {
15136   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15137
15138   if (gtk_widget_get_realized (widget))
15139     {
15140       gdk_window_set_background (tree_view->priv->bin_window,
15141                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15142     }
15143
15144   gtk_widget_queue_draw (widget);
15145 }
15146
15147 /**
15148  * gtk_tree_view_get_grid_lines:
15149  * @tree_view: a #GtkTreeView
15150  *
15151  * Returns which grid lines are enabled in @tree_view.
15152  *
15153  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15154  * are enabled.
15155  *
15156  * Since: 2.10
15157  */
15158 GtkTreeViewGridLines
15159 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15160 {
15161   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15162
15163   return tree_view->priv->grid_lines;
15164 }
15165
15166 /**
15167  * gtk_tree_view_set_grid_lines:
15168  * @tree_view: a #GtkTreeView
15169  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15170  * enable.
15171  *
15172  * Sets which grid lines to draw in @tree_view.
15173  *
15174  * Since: 2.10
15175  */
15176 void
15177 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15178                               GtkTreeViewGridLines   grid_lines)
15179 {
15180   GtkTreeViewPrivate *priv;
15181   GtkWidget *widget;
15182   GtkTreeViewGridLines old_grid_lines;
15183
15184   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15185
15186   priv = tree_view->priv;
15187   widget = GTK_WIDGET (tree_view);
15188
15189   old_grid_lines = priv->grid_lines;
15190   priv->grid_lines = grid_lines;
15191   
15192   if (gtk_widget_get_realized (widget))
15193     {
15194       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15195           priv->grid_line_width)
15196         {
15197           priv->grid_line_width = 0;
15198         }
15199       
15200       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15201           !priv->grid_line_width)
15202         {
15203           gint8 *dash_list;
15204
15205           gtk_widget_style_get (widget,
15206                                 "grid-line-width", &priv->grid_line_width,
15207                                 "grid-line-pattern", (gchar *)&dash_list,
15208                                 NULL);
15209       
15210           if (dash_list)
15211             {
15212               priv->grid_line_dashes[0] = dash_list[0];
15213               if (dash_list[0])
15214                 priv->grid_line_dashes[1] = dash_list[1];
15215               
15216               g_free (dash_list);
15217             }
15218           else
15219             {
15220               priv->grid_line_dashes[0] = 1;
15221               priv->grid_line_dashes[1] = 1;
15222             }
15223         }      
15224     }
15225
15226   if (old_grid_lines != grid_lines)
15227     {
15228       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15229       
15230       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15231     }
15232 }
15233
15234 /**
15235  * gtk_tree_view_get_enable_tree_lines:
15236  * @tree_view: a #GtkTreeView.
15237  *
15238  * Returns whether or not tree lines are drawn in @tree_view.
15239  *
15240  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15241  * otherwise.
15242  *
15243  * Since: 2.10
15244  */
15245 gboolean
15246 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15247 {
15248   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15249
15250   return tree_view->priv->tree_lines_enabled;
15251 }
15252
15253 /**
15254  * gtk_tree_view_set_enable_tree_lines:
15255  * @tree_view: a #GtkTreeView
15256  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15257  *
15258  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15259  * This does not have any visible effects for lists.
15260  *
15261  * Since: 2.10
15262  */
15263 void
15264 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15265                                      gboolean     enabled)
15266 {
15267   GtkTreeViewPrivate *priv;
15268   GtkWidget *widget;
15269   gboolean was_enabled;
15270
15271   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15272
15273   enabled = enabled != FALSE;
15274
15275   priv = tree_view->priv;
15276   widget = GTK_WIDGET (tree_view);
15277
15278   was_enabled = priv->tree_lines_enabled;
15279
15280   priv->tree_lines_enabled = enabled;
15281
15282   if (gtk_widget_get_realized (widget))
15283     {
15284       if (!enabled && priv->tree_line_width)
15285         {
15286           priv->tree_line_width = 0;
15287         }
15288       
15289       if (enabled && !priv->tree_line_width)
15290         {
15291           gint8 *dash_list;
15292           gtk_widget_style_get (widget,
15293                                 "tree-line-width", &priv->tree_line_width,
15294                                 "tree-line-pattern", (gchar *)&dash_list,
15295                                 NULL);
15296           
15297           if (dash_list)
15298             {
15299               priv->tree_line_dashes[0] = dash_list[0];
15300               if (dash_list[0])
15301                 priv->tree_line_dashes[1] = dash_list[1];
15302               
15303               g_free (dash_list);
15304             }
15305           else
15306             {
15307               priv->tree_line_dashes[0] = 1;
15308               priv->tree_line_dashes[1] = 1;
15309             }
15310         }
15311     }
15312
15313   if (was_enabled != enabled)
15314     {
15315       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15316
15317       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15318     }
15319 }
15320
15321
15322 /**
15323  * gtk_tree_view_set_show_expanders:
15324  * @tree_view: a #GtkTreeView
15325  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15326  *
15327  * Sets whether to draw and enable expanders and indent child rows in
15328  * @tree_view.  When disabled there will be no expanders visible in trees
15329  * and there will be no way to expand and collapse rows by default.  Also
15330  * note that hiding the expanders will disable the default indentation.  You
15331  * can set a custom indentation in this case using
15332  * gtk_tree_view_set_level_indentation().
15333  * This does not have any visible effects for lists.
15334  *
15335  * Since: 2.12
15336  */
15337 void
15338 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15339                                   gboolean     enabled)
15340 {
15341   gboolean was_enabled;
15342
15343   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15344
15345   enabled = enabled != FALSE;
15346   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15347
15348   if (enabled)
15349     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15350   else
15351     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15352
15353   if (enabled != was_enabled)
15354     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15355 }
15356
15357 /**
15358  * gtk_tree_view_get_show_expanders:
15359  * @tree_view: a #GtkTreeView.
15360  *
15361  * Returns whether or not expanders are drawn in @tree_view.
15362  *
15363  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15364  * otherwise.
15365  *
15366  * Since: 2.12
15367  */
15368 gboolean
15369 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15370 {
15371   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15372
15373   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15374 }
15375
15376 /**
15377  * gtk_tree_view_set_level_indentation:
15378  * @tree_view: a #GtkTreeView
15379  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15380  *
15381  * Sets the amount of extra indentation for child levels to use in @tree_view
15382  * in addition to the default indentation.  The value should be specified in
15383  * pixels, a value of 0 disables this feature and in this case only the default
15384  * indentation will be used.
15385  * This does not have any visible effects for lists.
15386  *
15387  * Since: 2.12
15388  */
15389 void
15390 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15391                                      gint         indentation)
15392 {
15393   tree_view->priv->level_indentation = indentation;
15394
15395   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15396 }
15397
15398 /**
15399  * gtk_tree_view_get_level_indentation:
15400  * @tree_view: a #GtkTreeView.
15401  *
15402  * Returns the amount, in pixels, of extra indentation for child levels
15403  * in @tree_view.
15404  *
15405  * Return value: the amount of extra indentation for child levels in
15406  * @tree_view.  A return value of 0 means that this feature is disabled.
15407  *
15408  * Since: 2.12
15409  */
15410 gint
15411 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15412 {
15413   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15414
15415   return tree_view->priv->level_indentation;
15416 }
15417
15418 /**
15419  * gtk_tree_view_set_tooltip_row:
15420  * @tree_view: a #GtkTreeView
15421  * @tooltip: a #GtkTooltip
15422  * @path: a #GtkTreePath
15423  *
15424  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15425  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15426  * See also gtk_tooltip_set_tip_area().
15427  *
15428  * Since: 2.12
15429  */
15430 void
15431 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15432                                GtkTooltip  *tooltip,
15433                                GtkTreePath *path)
15434 {
15435   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15436   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15437
15438   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15439 }
15440
15441 /**
15442  * gtk_tree_view_set_tooltip_cell:
15443  * @tree_view: a #GtkTreeView
15444  * @tooltip: a #GtkTooltip
15445  * @path: (allow-none): a #GtkTreePath or %NULL
15446  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15447  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15448  *
15449  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15450  * in common.  For example if @path is %NULL and @column is set, the tip
15451  * area will be set to the full area covered by @column.  See also
15452  * gtk_tooltip_set_tip_area().
15453  *
15454  * Note that if @path is not specified and @cell is set and part of a column
15455  * containing the expander, the tooltip might not show and hide at the correct
15456  * position.  In such cases @path must be set to the current node under the
15457  * mouse cursor for this function to operate correctly.
15458  *
15459  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15460  *
15461  * Since: 2.12
15462  */
15463 void
15464 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15465                                 GtkTooltip        *tooltip,
15466                                 GtkTreePath       *path,
15467                                 GtkTreeViewColumn *column,
15468                                 GtkCellRenderer   *cell)
15469 {
15470   GtkAllocation allocation;
15471   GdkRectangle rect;
15472
15473   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15474   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15475   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15476   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15477
15478   /* Determine x values. */
15479   if (column && cell)
15480     {
15481       GdkRectangle tmp;
15482       gint start, width;
15483
15484       /* We always pass in path here, whether it is NULL or not.
15485        * For cells in expander columns path must be specified so that
15486        * we can correctly account for the indentation.  This also means
15487        * that the tooltip is constrained vertically by the "Determine y
15488        * values" code below; this is not a real problem since cells actually
15489        * don't stretch vertically in constrast to columns.
15490        */
15491       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15492       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15493
15494       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15495                                                          tmp.x + start, 0,
15496                                                          &rect.x, NULL);
15497       rect.width = width;
15498     }
15499   else if (column)
15500     {
15501       GdkRectangle tmp;
15502
15503       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15504       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15505                                                          tmp.x, 0,
15506                                                          &rect.x, NULL);
15507       rect.width = tmp.width;
15508     }
15509   else
15510     {
15511       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15512       rect.x = 0;
15513       rect.width = allocation.width;
15514     }
15515
15516   /* Determine y values. */
15517   if (path)
15518     {
15519       GdkRectangle tmp;
15520
15521       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15522       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15523                                                          0, tmp.y,
15524                                                          NULL, &rect.y);
15525       rect.height = tmp.height;
15526     }
15527   else
15528     {
15529       rect.y = 0;
15530       rect.height = tree_view->priv->vadjustment->page_size;
15531     }
15532
15533   gtk_tooltip_set_tip_area (tooltip, &rect);
15534 }
15535
15536 /**
15537  * gtk_tree_view_get_tooltip_context:
15538  * @tree_view: a #GtkTreeView
15539  * @x: the x coordinate (relative to widget coordinates)
15540  * @y: the y coordinate (relative to widget coordinates)
15541  * @keyboard_tip: whether this is a keyboard tooltip or not
15542  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15543  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15544  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15545  *
15546  * This function is supposed to be used in a #GtkWidget::query-tooltip
15547  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15548  * which are received in the signal handler, should be passed to this
15549  * function without modification.
15550  *
15551  * The return value indicates whether there is a tree view row at the given
15552  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15553  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15554  * @model, @path and @iter which have been provided will be set to point to
15555  * that row and the corresponding model.  @x and @y will always be converted
15556  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15557  *
15558  * Return value: whether or not the given tooltip context points to a row.
15559  *
15560  * Since: 2.12
15561  */
15562 gboolean
15563 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15564                                    gint          *x,
15565                                    gint          *y,
15566                                    gboolean       keyboard_tip,
15567                                    GtkTreeModel **model,
15568                                    GtkTreePath  **path,
15569                                    GtkTreeIter   *iter)
15570 {
15571   GtkTreePath *tmppath = NULL;
15572
15573   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15574   g_return_val_if_fail (x != NULL, FALSE);
15575   g_return_val_if_fail (y != NULL, FALSE);
15576
15577   if (keyboard_tip)
15578     {
15579       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15580
15581       if (!tmppath)
15582         return FALSE;
15583     }
15584   else
15585     {
15586       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15587                                                          x, y);
15588
15589       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15590                                           &tmppath, NULL, NULL, NULL))
15591         return FALSE;
15592     }
15593
15594   if (model)
15595     *model = gtk_tree_view_get_model (tree_view);
15596
15597   if (iter)
15598     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15599                              iter, tmppath);
15600
15601   if (path)
15602     *path = tmppath;
15603   else
15604     gtk_tree_path_free (tmppath);
15605
15606   return TRUE;
15607 }
15608
15609 static gboolean
15610 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15611                                     gint        x,
15612                                     gint        y,
15613                                     gboolean    keyboard_tip,
15614                                     GtkTooltip *tooltip,
15615                                     gpointer    data)
15616 {
15617   GValue value = { 0, };
15618   GValue transformed = { 0, };
15619   GtkTreeIter iter;
15620   GtkTreePath *path;
15621   GtkTreeModel *model;
15622   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15623
15624   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15625                                           &x, &y,
15626                                           keyboard_tip,
15627                                           &model, &path, &iter))
15628     return FALSE;
15629
15630   gtk_tree_model_get_value (model, &iter,
15631                             tree_view->priv->tooltip_column, &value);
15632
15633   g_value_init (&transformed, G_TYPE_STRING);
15634
15635   if (!g_value_transform (&value, &transformed))
15636     {
15637       g_value_unset (&value);
15638       gtk_tree_path_free (path);
15639
15640       return FALSE;
15641     }
15642
15643   g_value_unset (&value);
15644
15645   if (!g_value_get_string (&transformed))
15646     {
15647       g_value_unset (&transformed);
15648       gtk_tree_path_free (path);
15649
15650       return FALSE;
15651     }
15652
15653   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15654   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15655
15656   gtk_tree_path_free (path);
15657   g_value_unset (&transformed);
15658
15659   return TRUE;
15660 }
15661
15662 /**
15663  * gtk_tree_view_set_tooltip_column:
15664  * @tree_view: a #GtkTreeView
15665  * @column: an integer, which is a valid column number for @tree_view's model
15666  *
15667  * If you only plan to have simple (text-only) tooltips on full rows, you
15668  * can use this function to have #GtkTreeView handle these automatically
15669  * for you. @column should be set to the column in @tree_view's model
15670  * containing the tooltip texts, or -1 to disable this feature.
15671  *
15672  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15673  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15674  *
15675  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15676  * so &amp;, &lt;, etc have to be escaped in the text.
15677  *
15678  * Since: 2.12
15679  */
15680 void
15681 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15682                                   gint         column)
15683 {
15684   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15685
15686   if (column == tree_view->priv->tooltip_column)
15687     return;
15688
15689   if (column == -1)
15690     {
15691       g_signal_handlers_disconnect_by_func (tree_view,
15692                                             gtk_tree_view_set_tooltip_query_cb,
15693                                             NULL);
15694       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15695     }
15696   else
15697     {
15698       if (tree_view->priv->tooltip_column == -1)
15699         {
15700           g_signal_connect (tree_view, "query-tooltip",
15701                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15702           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15703         }
15704     }
15705
15706   tree_view->priv->tooltip_column = column;
15707   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15708 }
15709
15710 /**
15711  * gtk_tree_view_get_tooltip_column:
15712  * @tree_view: a #GtkTreeView
15713  *
15714  * Returns the column of @tree_view's model which is being used for
15715  * displaying tooltips on @tree_view's rows.
15716  *
15717  * Return value: the index of the tooltip column that is currently being
15718  * used, or -1 if this is disabled.
15719  *
15720  * Since: 2.12
15721  */
15722 gint
15723 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15724 {
15725   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15726
15727   return tree_view->priv->tooltip_column;
15728 }