]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Use gtk_size_request_get_size() instead deprecated gtk_widget_size_request()
[~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 <string.h>
23 #include <gdk/gdkkeysyms.h>
24
25 #include "gtktreeview.h"
26 #include "gtkrbtree.h"
27 #include "gtktreednd.h"
28 #include "gtktreeprivate.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtkalignment.h"
35 #include "gtklabel.h"
36 #include "gtkhbox.h"
37 #include "gtkvbox.h"
38 #include "gtkarrow.h"
39 #include "gtkintl.h"
40 #include "gtkbindings.h"
41 #include "gtkcontainer.h"
42 #include "gtkentry.h"
43 #include "gtkframe.h"
44 #include "gtktreemodelsort.h"
45 #include "gtktooltip.h"
46 #include "gtksizerequest.h"
47 #include "gtkprivate.h"
48
49 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
50 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
51 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
52 #define SCROLL_EDGE_SIZE 15
53 #define EXPANDER_EXTRA_PADDING 4
54 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
55 #define AUTO_EXPAND_TIMEOUT 500
56
57 /* The "background" areas of all rows/cells add up to cover the entire tree.
58  * The background includes all inter-row and inter-cell spacing.
59  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
60  * i.e. just the cells, no spacing.
61  */
62
63 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
64 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
65
66 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
67  * vice versa.
68  */
69 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
70 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
71
72 /* This is in bin_window coordinates */
73 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
74 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
75
76 #define ROW_HEIGHT(tree_view,height) \
77   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
78
79
80 typedef struct _GtkTreeViewChild GtkTreeViewChild;
81 struct _GtkTreeViewChild
82 {
83   GtkWidget *widget;
84   gint x;
85   gint y;
86   gint width;
87   gint height;
88 };
89
90
91 typedef struct _TreeViewDragInfo TreeViewDragInfo;
92 struct _TreeViewDragInfo
93 {
94   GdkModifierType start_button_mask;
95   GtkTargetList *_unused_source_target_list;
96   GdkDragAction source_actions;
97
98   GtkTargetList *_unused_dest_target_list;
99
100   guint source_set : 1;
101   guint dest_set : 1;
102 };
103
104
105 /* Signals */
106 enum
107 {
108   ROW_ACTIVATED,
109   TEST_EXPAND_ROW,
110   TEST_COLLAPSE_ROW,
111   ROW_EXPANDED,
112   ROW_COLLAPSED,
113   COLUMNS_CHANGED,
114   CURSOR_CHANGED,
115   MOVE_CURSOR,
116   SELECT_ALL,
117   UNSELECT_ALL,
118   SELECT_CURSOR_ROW,
119   TOGGLE_CURSOR_ROW,
120   EXPAND_COLLAPSE_CURSOR_ROW,
121   SELECT_CURSOR_PARENT,
122   START_INTERACTIVE_SEARCH,
123   LAST_SIGNAL
124 };
125
126 /* Properties */
127 enum {
128   PROP_0,
129   PROP_MODEL,
130   PROP_HADJUSTMENT,
131   PROP_VADJUSTMENT,
132   PROP_HEADERS_VISIBLE,
133   PROP_HEADERS_CLICKABLE,
134   PROP_EXPANDER_COLUMN,
135   PROP_REORDERABLE,
136   PROP_RULES_HINT,
137   PROP_ENABLE_SEARCH,
138   PROP_SEARCH_COLUMN,
139   PROP_FIXED_HEIGHT_MODE,
140   PROP_HOVER_SELECTION,
141   PROP_HOVER_EXPAND,
142   PROP_SHOW_EXPANDERS,
143   PROP_LEVEL_INDENTATION,
144   PROP_RUBBER_BANDING,
145   PROP_ENABLE_GRID_LINES,
146   PROP_ENABLE_TREE_LINES,
147   PROP_TOOLTIP_COLUMN
148 };
149
150 /* object signals */
151 static void     gtk_tree_view_finalize             (GObject          *object);
152 static void     gtk_tree_view_set_property         (GObject         *object,
153                                                     guint            prop_id,
154                                                     const GValue    *value,
155                                                     GParamSpec      *pspec);
156 static void     gtk_tree_view_get_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     GValue          *value,
159                                                     GParamSpec      *pspec);
160
161 /* gtkobject signals */
162 static void     gtk_tree_view_destroy              (GtkObject        *object);
163
164 /* gtkwidget signals */
165 static void     gtk_tree_view_realize              (GtkWidget        *widget);
166 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
167 static void     gtk_tree_view_map                  (GtkWidget        *widget);
168 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
169                                                     GtkRequisition   *requisition);
170 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
171                                                     GtkAllocation    *allocation);
172 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
173                                                     GdkEventExpose   *event);
174 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
175                                                     GdkEventKey      *event);
176 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
177                                                     GdkEventKey      *event);
178 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
179                                                     GdkEventMotion   *event);
180 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
181                                                     GdkEventCrossing *event);
182 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
183                                                     GdkEventCrossing *event);
184 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
185                                                     GdkEventButton   *event);
186 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
187                                                     GdkEventButton   *event);
188 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
189                                                     GdkEventGrabBroken *event);
190 #if 0
191 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
192                                                     GdkEventConfigure *event);
193 #endif
194
195 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
196                                                     GtkWidget        *child);
197 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
198                                                     GdkEventFocus    *event);
199 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
200                                                     GtkDirectionType  direction);
201 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
202 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
203                                                     GtkStyle         *previous_style);
204 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
205                                                     gboolean          was_grabbed);
206 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
207                                                     GtkStateType      previous_state);
208
209 /* container signals */
210 static void     gtk_tree_view_remove               (GtkContainer     *container,
211                                                     GtkWidget        *widget);
212 static void     gtk_tree_view_forall               (GtkContainer     *container,
213                                                     gboolean          include_internals,
214                                                     GtkCallback       callback,
215                                                     gpointer          callback_data);
216
217 /* Source side drag signals */
218 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
219                                             GdkDragContext   *context);
220 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
221                                             GdkDragContext   *context);
222 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
223                                             GdkDragContext   *context,
224                                             GtkSelectionData *selection_data,
225                                             guint             info,
226                                             guint             time);
227 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
228                                             GdkDragContext   *context);
229
230 /* Target side drag signals */
231 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
232                                                   GdkDragContext   *context,
233                                                   guint             time);
234 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
235                                                   GdkDragContext   *context,
236                                                   gint              x,
237                                                   gint              y,
238                                                   guint             time);
239 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
240                                                   GdkDragContext   *context,
241                                                   gint              x,
242                                                   gint              y,
243                                                   guint             time);
244 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
245                                                   GdkDragContext   *context,
246                                                   gint              x,
247                                                   gint              y,
248                                                   GtkSelectionData *selection_data,
249                                                   guint             info,
250                                                   guint             time);
251
252 /* tree_model signals */
253 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
254                                                            GtkAdjustment   *hadj,
255                                                            GtkAdjustment   *vadj);
256 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
257                                                            GtkMovementStep  step,
258                                                            gint             count);
259 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
261 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
262                                                            gboolean         start_editing);
263 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
264 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
265                                                                gboolean         logical,
266                                                                gboolean         expand,
267                                                                gboolean         open_all);
268 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
269 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
270                                                            GtkTreePath     *path,
271                                                            GtkTreeIter     *iter,
272                                                            gpointer         data);
273 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
274                                                            GtkTreePath     *path,
275                                                            GtkTreeIter     *iter,
276                                                            gpointer         data);
277 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
278                                                            GtkTreePath     *path,
279                                                            GtkTreeIter     *iter,
280                                                            gpointer         data);
281 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
282                                                            GtkTreePath     *path,
283                                                            gpointer         data);
284 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
285                                                            GtkTreePath     *parent,
286                                                            GtkTreeIter     *iter,
287                                                            gint            *new_order,
288                                                            gpointer         data);
289
290 /* Incremental reflow */
291 static gboolean validate_row             (GtkTreeView *tree_view,
292                                           GtkRBTree   *tree,
293                                           GtkRBNode   *node,
294                                           GtkTreeIter *iter,
295                                           GtkTreePath *path);
296 static void     validate_visible_area    (GtkTreeView *tree_view);
297 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
298 static gboolean do_validate_rows         (GtkTreeView *tree_view,
299                                           gboolean     size_request);
300 static gboolean validate_rows            (GtkTreeView *tree_view);
301 static gboolean presize_handler_callback (gpointer     data);
302 static void     install_presize_handler  (GtkTreeView *tree_view);
303 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
304 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
305                                              GtkTreePath *path,
306                                              gint         offset);
307 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
308 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
309 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
310
311 /* Internal functions */
312 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
313                                                               GtkTreeViewColumn  *column);
314 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
315                                                               guint               keyval,
316                                                               guint               modmask,
317                                                               gboolean            add_shifted_binding,
318                                                               GtkMovementStep     step,
319                                                               gint                count);
320 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
321                                                               GtkRBTree          *tree);
322 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
323                                                               GtkTreePath        *path,
324                                                               const GdkRectangle *clip_rect);
325 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
326                                                               GtkRBTree          *tree,
327                                                               GtkRBNode          *node,
328                                                               const GdkRectangle *clip_rect);
329 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
330                                                               GtkRBTree          *tree,
331                                                               GtkRBNode          *node,
332                                                               gint                x,
333                                                               gint                y);
334 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
335                                                               GtkRBTree          *tree,
336                                                               gint               *x1,
337                                                               gint               *x2);
338 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
339                                                               gint                i,
340                                                               gint               *x);
341 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
342                                                               GtkTreeView        *tree_view);
343 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
344                                                               GtkRBTree          *tree,
345                                                               GtkTreeIter        *iter,
346                                                               gint                depth,
347                                                               gboolean            recurse);
348 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
349                                                               GtkRBTree          *tree,
350                                                               GtkRBNode          *node);
351 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
352                                                               GtkTreeViewColumn  *column,
353                                                               gboolean            focus_to_cell);
354 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
355                                                               GdkEventMotion     *event);
356 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
357 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
358                                                               gint                count);
359 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
360                                                               gint                count);
361 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
362                                                               gint                count);
363 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
364                                                               gint                count);
365 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
366                                                               GtkTreePath        *path,
367                                                               GtkRBTree          *tree,
368                                                               GtkRBNode          *node,
369                                                               gboolean            animate);
370 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
371                                                               GtkTreePath        *path,
372                                                               GtkRBTree          *tree,
373                                                               GtkRBNode          *node,
374                                                               gboolean            open_all,
375                                                               gboolean            animate);
376 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
377                                                               GtkTreePath        *path,
378                                                               gboolean            clear_and_select,
379                                                               gboolean            clamp_node);
380 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
381 static void     column_sizing_notify                         (GObject            *object,
382                                                               GParamSpec         *pspec,
383                                                               gpointer            data);
384 static gboolean expand_collapse_timeout                      (gpointer            data);
385 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
386                                                               GtkRBTree          *tree,
387                                                               GtkRBNode          *node,
388                                                               gboolean            expand);
389 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
390 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
391 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
392 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
393 static void     update_prelight                              (GtkTreeView        *tree_view,
394                                                               int                 x,
395                                                               int                 y);
396
397 /* interactive search */
398 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
399 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
400                                                          GtkTreeView      *tree_view,
401                                                          GdkDevice        *device);
402 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
403                                                          GtkWidget        *search_dialog,
404                                                          gpointer          user_data);
405 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
406                                                          GtkMenu          *menu,
407                                                          gpointer          data);
408 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
409                                                          GtkTreeView      *tree_view);
410 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
411                                                          GtkTreeView      *tree_view);
412 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
413 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
414                                                          gpointer          data);
415 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
416                                                          GdkEventAny      *event,
417                                                          GtkTreeView      *tree_view);
418 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
419                                                          GdkEventButton   *event,
420                                                          GtkTreeView      *tree_view);
421 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
422                                                          GdkEventScroll   *event,
423                                                          GtkTreeView      *tree_view);
424 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
425                                                          GdkEventKey      *event,
426                                                          GtkTreeView      *tree_view);
427 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
428                                                          GtkTreeView      *tree_view,
429                                                          gboolean          up);
430 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
431                                                          gint              column,
432                                                          const gchar      *key,
433                                                          GtkTreeIter      *iter,
434                                                          gpointer          search_data);
435 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
436                                                          GtkTreeSelection *selection,
437                                                          GtkTreeIter      *iter,
438                                                          const gchar      *text,
439                                                          gint             *count,
440                                                          gint              n);
441 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
442                                                          GtkTreeView      *tree_view);
443 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
444                                                          GtkWidget        *child_widget,
445                                                          gint              x,
446                                                          gint              y,
447                                                          gint              width,
448                                                          gint              height);
449 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
450                                                          GtkTreePath      *cursor_path);
451 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
452                                               GtkTreeViewColumn *column,
453                                               GtkTreePath       *path,
454                                               GtkCellEditable   *cell_editable,
455                                               GdkRectangle      *cell_area,
456                                               GdkEvent          *event,
457                                               guint              flags);
458 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
459                                                          gboolean     cancel_editing);
460 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
461                                                              GdkDevice   *device,
462                                                              gboolean     keybinding);
463 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
464 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
465                                                          GtkTreeViewColumn *column,
466                                                          gint               drop_position);
467
468 /* GtkBuildable */
469 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
470                                                             GtkBuilder        *builder,
471                                                             GObject           *child,
472                                                             const gchar       *type);
473 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
474                                                             GtkBuilder        *builder,
475                                                             const gchar       *childname);
476 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
477
478
479 static gboolean scroll_row_timeout                   (gpointer     data);
480 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
481 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
482
483 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
484
485 \f
486
487 /* GType Methods
488  */
489
490 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
491                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
492                                                 gtk_tree_view_buildable_init))
493
494 static void
495 gtk_tree_view_class_init (GtkTreeViewClass *class)
496 {
497   GObjectClass *o_class;
498   GtkObjectClass *object_class;
499   GtkWidgetClass *widget_class;
500   GtkContainerClass *container_class;
501   GtkBindingSet *binding_set;
502
503   binding_set = gtk_binding_set_by_class (class);
504
505   o_class = (GObjectClass *) class;
506   object_class = (GtkObjectClass *) class;
507   widget_class = (GtkWidgetClass *) class;
508   container_class = (GtkContainerClass *) class;
509
510   /* GObject signals */
511   o_class->set_property = gtk_tree_view_set_property;
512   o_class->get_property = gtk_tree_view_get_property;
513   o_class->finalize = gtk_tree_view_finalize;
514
515   /* GtkObject signals */
516   object_class->destroy = gtk_tree_view_destroy;
517
518   /* GtkWidget signals */
519   widget_class->map = gtk_tree_view_map;
520   widget_class->realize = gtk_tree_view_realize;
521   widget_class->unrealize = gtk_tree_view_unrealize;
522   widget_class->size_request = gtk_tree_view_size_request;
523   widget_class->size_allocate = gtk_tree_view_size_allocate;
524   widget_class->button_press_event = gtk_tree_view_button_press;
525   widget_class->button_release_event = gtk_tree_view_button_release;
526   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
527   /*widget_class->configure_event = gtk_tree_view_configure;*/
528   widget_class->motion_notify_event = gtk_tree_view_motion;
529   widget_class->expose_event = gtk_tree_view_expose;
530   widget_class->key_press_event = gtk_tree_view_key_press;
531   widget_class->key_release_event = gtk_tree_view_key_release;
532   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
533   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
534   widget_class->focus_out_event = gtk_tree_view_focus_out;
535   widget_class->drag_begin = gtk_tree_view_drag_begin;
536   widget_class->drag_end = gtk_tree_view_drag_end;
537   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
538   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
539   widget_class->drag_leave = gtk_tree_view_drag_leave;
540   widget_class->drag_motion = gtk_tree_view_drag_motion;
541   widget_class->drag_drop = gtk_tree_view_drag_drop;
542   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
543   widget_class->focus = gtk_tree_view_focus;
544   widget_class->grab_focus = gtk_tree_view_grab_focus;
545   widget_class->style_set = gtk_tree_view_style_set;
546   widget_class->grab_notify = gtk_tree_view_grab_notify;
547   widget_class->state_changed = gtk_tree_view_state_changed;
548
549   /* GtkContainer signals */
550   container_class->remove = gtk_tree_view_remove;
551   container_class->forall = gtk_tree_view_forall;
552   container_class->set_focus_child = gtk_tree_view_set_focus_child;
553
554   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
555   class->move_cursor = gtk_tree_view_real_move_cursor;
556   class->select_all = gtk_tree_view_real_select_all;
557   class->unselect_all = gtk_tree_view_real_unselect_all;
558   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
559   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
560   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
561   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
562   class->start_interactive_search = gtk_tree_view_start_interactive_search;
563
564   /* Properties */
565
566   g_object_class_install_property (o_class,
567                                    PROP_MODEL,
568                                    g_param_spec_object ("model",
569                                                         P_("TreeView Model"),
570                                                         P_("The model for the tree view"),
571                                                         GTK_TYPE_TREE_MODEL,
572                                                         GTK_PARAM_READWRITE));
573
574   g_object_class_install_property (o_class,
575                                    PROP_HADJUSTMENT,
576                                    g_param_spec_object ("hadjustment",
577                                                         P_("Horizontal Adjustment"),
578                                                         P_("Horizontal Adjustment for the widget"),
579                                                         GTK_TYPE_ADJUSTMENT,
580                                                         GTK_PARAM_READWRITE));
581
582   g_object_class_install_property (o_class,
583                                    PROP_VADJUSTMENT,
584                                    g_param_spec_object ("vadjustment",
585                                                         P_("Vertical Adjustment"),
586                                                         P_("Vertical Adjustment for the widget"),
587                                                         GTK_TYPE_ADJUSTMENT,
588                                                         GTK_PARAM_READWRITE));
589
590   g_object_class_install_property (o_class,
591                                    PROP_HEADERS_VISIBLE,
592                                    g_param_spec_boolean ("headers-visible",
593                                                          P_("Headers Visible"),
594                                                          P_("Show the column header buttons"),
595                                                          TRUE,
596                                                          GTK_PARAM_READWRITE));
597
598   g_object_class_install_property (o_class,
599                                    PROP_HEADERS_CLICKABLE,
600                                    g_param_spec_boolean ("headers-clickable",
601                                                          P_("Headers Clickable"),
602                                                          P_("Column headers respond to click events"),
603                                                          TRUE,
604                                                          GTK_PARAM_READWRITE));
605
606   g_object_class_install_property (o_class,
607                                    PROP_EXPANDER_COLUMN,
608                                    g_param_spec_object ("expander-column",
609                                                         P_("Expander Column"),
610                                                         P_("Set the column for the expander column"),
611                                                         GTK_TYPE_TREE_VIEW_COLUMN,
612                                                         GTK_PARAM_READWRITE));
613
614   g_object_class_install_property (o_class,
615                                    PROP_REORDERABLE,
616                                    g_param_spec_boolean ("reorderable",
617                                                          P_("Reorderable"),
618                                                          P_("View is reorderable"),
619                                                          FALSE,
620                                                          GTK_PARAM_READWRITE));
621
622   g_object_class_install_property (o_class,
623                                    PROP_RULES_HINT,
624                                    g_param_spec_boolean ("rules-hint",
625                                                          P_("Rules Hint"),
626                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
627                                                          FALSE,
628                                                          GTK_PARAM_READWRITE));
629
630     g_object_class_install_property (o_class,
631                                      PROP_ENABLE_SEARCH,
632                                      g_param_spec_boolean ("enable-search",
633                                                            P_("Enable Search"),
634                                                            P_("View allows user to search through columns interactively"),
635                                                            TRUE,
636                                                            GTK_PARAM_READWRITE));
637
638     g_object_class_install_property (o_class,
639                                      PROP_SEARCH_COLUMN,
640                                      g_param_spec_int ("search-column",
641                                                        P_("Search Column"),
642                                                        P_("Model column to search through during interactive search"),
643                                                        -1,
644                                                        G_MAXINT,
645                                                        -1,
646                                                        GTK_PARAM_READWRITE));
647
648     /**
649      * GtkTreeView:fixed-height-mode:
650      *
651      * Setting the ::fixed-height-mode property to %TRUE speeds up 
652      * #GtkTreeView by assuming that all rows have the same height. 
653      * Only enable this option if all rows are the same height.  
654      * Please see gtk_tree_view_set_fixed_height_mode() for more 
655      * information on this option.
656      *
657      * Since: 2.4
658      **/
659     g_object_class_install_property (o_class,
660                                      PROP_FIXED_HEIGHT_MODE,
661                                      g_param_spec_boolean ("fixed-height-mode",
662                                                            P_("Fixed Height Mode"),
663                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
664                                                            FALSE,
665                                                            GTK_PARAM_READWRITE));
666     
667     /**
668      * GtkTreeView:hover-selection:
669      * 
670      * Enables or disables the hover selection mode of @tree_view.
671      * Hover selection makes the selected row follow the pointer.
672      * Currently, this works only for the selection modes 
673      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
674      *
675      * This mode is primarily intended for treeviews in popups, e.g.
676      * in #GtkComboBox or #GtkEntryCompletion.
677      *
678      * Since: 2.6
679      */
680     g_object_class_install_property (o_class,
681                                      PROP_HOVER_SELECTION,
682                                      g_param_spec_boolean ("hover-selection",
683                                                            P_("Hover Selection"),
684                                                            P_("Whether the selection should follow the pointer"),
685                                                            FALSE,
686                                                            GTK_PARAM_READWRITE));
687
688     /**
689      * GtkTreeView:hover-expand:
690      * 
691      * Enables or disables the hover expansion mode of @tree_view.
692      * Hover expansion makes rows expand or collapse if the pointer moves 
693      * over them.
694      *
695      * This mode is primarily intended for treeviews in popups, e.g.
696      * in #GtkComboBox or #GtkEntryCompletion.
697      *
698      * Since: 2.6
699      */
700     g_object_class_install_property (o_class,
701                                      PROP_HOVER_EXPAND,
702                                      g_param_spec_boolean ("hover-expand",
703                                                            P_("Hover Expand"),
704                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
705                                                            FALSE,
706                                                            GTK_PARAM_READWRITE));
707
708     /**
709      * GtkTreeView:show-expanders:
710      *
711      * %TRUE if the view has expanders.
712      *
713      * Since: 2.12
714      */
715     g_object_class_install_property (o_class,
716                                      PROP_SHOW_EXPANDERS,
717                                      g_param_spec_boolean ("show-expanders",
718                                                            P_("Show Expanders"),
719                                                            P_("View has expanders"),
720                                                            TRUE,
721                                                            GTK_PARAM_READWRITE));
722
723     /**
724      * GtkTreeView:level-indentation:
725      *
726      * Extra indentation for each level.
727      *
728      * Since: 2.12
729      */
730     g_object_class_install_property (o_class,
731                                      PROP_LEVEL_INDENTATION,
732                                      g_param_spec_int ("level-indentation",
733                                                        P_("Level Indentation"),
734                                                        P_("Extra indentation for each level"),
735                                                        0,
736                                                        G_MAXINT,
737                                                        0,
738                                                        GTK_PARAM_READWRITE));
739
740     g_object_class_install_property (o_class,
741                                      PROP_RUBBER_BANDING,
742                                      g_param_spec_boolean ("rubber-banding",
743                                                            P_("Rubber Banding"),
744                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
745                                                            FALSE,
746                                                            GTK_PARAM_READWRITE));
747
748     g_object_class_install_property (o_class,
749                                      PROP_ENABLE_GRID_LINES,
750                                      g_param_spec_enum ("enable-grid-lines",
751                                                         P_("Enable Grid Lines"),
752                                                         P_("Whether grid lines should be drawn in the tree view"),
753                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
754                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
755                                                         GTK_PARAM_READWRITE));
756
757     g_object_class_install_property (o_class,
758                                      PROP_ENABLE_TREE_LINES,
759                                      g_param_spec_boolean ("enable-tree-lines",
760                                                            P_("Enable Tree Lines"),
761                                                            P_("Whether tree lines should be drawn in the tree view"),
762                                                            FALSE,
763                                                            GTK_PARAM_READWRITE));
764
765     g_object_class_install_property (o_class,
766                                      PROP_TOOLTIP_COLUMN,
767                                      g_param_spec_int ("tooltip-column",
768                                                        P_("Tooltip Column"),
769                                                        P_("The column in the model containing the tooltip texts for the rows"),
770                                                        -1,
771                                                        G_MAXINT,
772                                                        -1,
773                                                        GTK_PARAM_READWRITE));
774
775   /* Style properties */
776 #define _TREE_VIEW_EXPANDER_SIZE 12
777 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
778 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
779
780   gtk_widget_class_install_style_property (widget_class,
781                                            g_param_spec_int ("expander-size",
782                                                              P_("Expander Size"),
783                                                              P_("Size of the expander arrow"),
784                                                              0,
785                                                              G_MAXINT,
786                                                              _TREE_VIEW_EXPANDER_SIZE,
787                                                              GTK_PARAM_READABLE));
788
789   gtk_widget_class_install_style_property (widget_class,
790                                            g_param_spec_int ("vertical-separator",
791                                                              P_("Vertical Separator Width"),
792                                                              P_("Vertical space between cells.  Must be an even number"),
793                                                              0,
794                                                              G_MAXINT,
795                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
796                                                              GTK_PARAM_READABLE));
797
798   gtk_widget_class_install_style_property (widget_class,
799                                            g_param_spec_int ("horizontal-separator",
800                                                              P_("Horizontal Separator Width"),
801                                                              P_("Horizontal space between cells.  Must be an even number"),
802                                                              0,
803                                                              G_MAXINT,
804                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
805                                                              GTK_PARAM_READABLE));
806
807   gtk_widget_class_install_style_property (widget_class,
808                                            g_param_spec_boolean ("allow-rules",
809                                                                  P_("Allow Rules"),
810                                                                  P_("Allow drawing of alternating color rows"),
811                                                                  TRUE,
812                                                                  GTK_PARAM_READABLE));
813
814   gtk_widget_class_install_style_property (widget_class,
815                                            g_param_spec_boolean ("indent-expanders",
816                                                                  P_("Indent Expanders"),
817                                                                  P_("Make the expanders indented"),
818                                                                  TRUE,
819                                                                  GTK_PARAM_READABLE));
820
821   gtk_widget_class_install_style_property (widget_class,
822                                            g_param_spec_boxed ("even-row-color",
823                                                                P_("Even Row Color"),
824                                                                P_("Color to use for even rows"),
825                                                                GDK_TYPE_COLOR,
826                                                                GTK_PARAM_READABLE));
827
828   gtk_widget_class_install_style_property (widget_class,
829                                            g_param_spec_boxed ("odd-row-color",
830                                                                P_("Odd Row Color"),
831                                                                P_("Color to use for odd rows"),
832                                                                GDK_TYPE_COLOR,
833                                                                GTK_PARAM_READABLE));
834
835   gtk_widget_class_install_style_property (widget_class,
836                                            g_param_spec_int ("grid-line-width",
837                                                              P_("Grid line width"),
838                                                              P_("Width, in pixels, of the tree view grid lines"),
839                                                              0, G_MAXINT, 1,
840                                                              GTK_PARAM_READABLE));
841
842   gtk_widget_class_install_style_property (widget_class,
843                                            g_param_spec_int ("tree-line-width",
844                                                              P_("Tree line width"),
845                                                              P_("Width, in pixels, of the tree view lines"),
846                                                              0, G_MAXINT, 1,
847                                                              GTK_PARAM_READABLE));
848
849   gtk_widget_class_install_style_property (widget_class,
850                                            g_param_spec_string ("grid-line-pattern",
851                                                                 P_("Grid line pattern"),
852                                                                 P_("Dash pattern used to draw the tree view grid lines"),
853                                                                 "\1\1",
854                                                                 GTK_PARAM_READABLE));
855
856   gtk_widget_class_install_style_property (widget_class,
857                                            g_param_spec_string ("tree-line-pattern",
858                                                                 P_("Tree line pattern"),
859                                                                 P_("Dash pattern used to draw the tree view lines"),
860                                                                 "\1\1",
861                                                                 GTK_PARAM_READABLE));
862
863   /* Signals */
864   /**
865    * GtkTreeView::set-scroll-adjustments
866    * @horizontal: the horizontal #GtkAdjustment
867    * @vertical: the vertical #GtkAdjustment
868    *
869    * Set the scroll adjustments for the tree view. Usually scrolled containers
870    * like #GtkScrolledWindow will emit this signal to connect two instances
871    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
872    */
873   widget_class->set_scroll_adjustments_signal =
874     g_signal_new (I_("set-scroll-adjustments"),
875                   G_TYPE_FROM_CLASS (o_class),
876                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
877                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
878                   NULL, NULL,
879                   _gtk_marshal_VOID__OBJECT_OBJECT,
880                   G_TYPE_NONE, 2,
881                   GTK_TYPE_ADJUSTMENT,
882                   GTK_TYPE_ADJUSTMENT);
883
884   /**
885    * GtkTreeView::row-activated:
886    * @tree_view: the object on which the signal is emitted
887    * @path: the #GtkTreePath for the activated row
888    * @column: the #GtkTreeViewColumn in which the activation occurred
889    *
890    * The "row-activated" signal is emitted when the method
891    * gtk_tree_view_row_activated() is called or the user double clicks 
892    * a treeview row. It is also emitted when a non-editable row is 
893    * selected and one of the keys: Space, Shift+Space, Return or 
894    * Enter is pressed.
895    * 
896    * For selection handling refer to the <link linkend="TreeWidget">tree 
897    * widget conceptual overview</link> as well as #GtkTreeSelection.
898    */
899   tree_view_signals[ROW_ACTIVATED] =
900     g_signal_new (I_("row-activated"),
901                   G_TYPE_FROM_CLASS (o_class),
902                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
903                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
904                   NULL, NULL,
905                   _gtk_marshal_VOID__BOXED_OBJECT,
906                   G_TYPE_NONE, 2,
907                   GTK_TYPE_TREE_PATH,
908                   GTK_TYPE_TREE_VIEW_COLUMN);
909
910   /**
911    * GtkTreeView::test-expand-row:
912    * @tree_view: the object on which the signal is emitted
913    * @iter: the tree iter of the row to expand
914    * @path: a tree path that points to the row 
915    * 
916    * The given row is about to be expanded (show its children nodes). Use this
917    * signal if you need to control the expandability of individual rows.
918    *
919    * Returns: %FALSE to allow expansion, %TRUE to reject
920    */
921   tree_view_signals[TEST_EXPAND_ROW] =
922     g_signal_new (I_("test-expand-row"),
923                   G_TYPE_FROM_CLASS (o_class),
924                   G_SIGNAL_RUN_LAST,
925                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
926                   _gtk_boolean_handled_accumulator, NULL,
927                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
928                   G_TYPE_BOOLEAN, 2,
929                   GTK_TYPE_TREE_ITER,
930                   GTK_TYPE_TREE_PATH);
931
932   /**
933    * GtkTreeView::test-collapse-row:
934    * @tree_view: the object on which the signal is emitted
935    * @iter: the tree iter of the row to collapse
936    * @path: a tree path that points to the row 
937    * 
938    * The given row is about to be collapsed (hide its children nodes). Use this
939    * signal if you need to control the collapsibility of individual rows.
940    *
941    * Returns: %FALSE to allow collapsing, %TRUE to reject
942    */
943   tree_view_signals[TEST_COLLAPSE_ROW] =
944     g_signal_new (I_("test-collapse-row"),
945                   G_TYPE_FROM_CLASS (o_class),
946                   G_SIGNAL_RUN_LAST,
947                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
948                   _gtk_boolean_handled_accumulator, NULL,
949                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
950                   G_TYPE_BOOLEAN, 2,
951                   GTK_TYPE_TREE_ITER,
952                   GTK_TYPE_TREE_PATH);
953
954   /**
955    * GtkTreeView::row-expanded:
956    * @tree_view: the object on which the signal is emitted
957    * @iter: the tree iter of the expanded row
958    * @path: a tree path that points to the row 
959    * 
960    * The given row has been expanded (child nodes are shown).
961    */
962   tree_view_signals[ROW_EXPANDED] =
963     g_signal_new (I_("row-expanded"),
964                   G_TYPE_FROM_CLASS (o_class),
965                   G_SIGNAL_RUN_LAST,
966                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
967                   NULL, NULL,
968                   _gtk_marshal_VOID__BOXED_BOXED,
969                   G_TYPE_NONE, 2,
970                   GTK_TYPE_TREE_ITER,
971                   GTK_TYPE_TREE_PATH);
972
973   /**
974    * GtkTreeView::row-collapsed:
975    * @tree_view: the object on which the signal is emitted
976    * @iter: the tree iter of the collapsed row
977    * @path: a tree path that points to the row 
978    * 
979    * The given row has been collapsed (child nodes are hidden).
980    */
981   tree_view_signals[ROW_COLLAPSED] =
982     g_signal_new (I_("row-collapsed"),
983                   G_TYPE_FROM_CLASS (o_class),
984                   G_SIGNAL_RUN_LAST,
985                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
986                   NULL, NULL,
987                   _gtk_marshal_VOID__BOXED_BOXED,
988                   G_TYPE_NONE, 2,
989                   GTK_TYPE_TREE_ITER,
990                   GTK_TYPE_TREE_PATH);
991
992   /**
993    * GtkTreeView::columns-changed:
994    * @tree_view: the object on which the signal is emitted 
995    * 
996    * The number of columns of the treeview has changed.
997    */
998   tree_view_signals[COLUMNS_CHANGED] =
999     g_signal_new (I_("columns-changed"),
1000                   G_TYPE_FROM_CLASS (o_class),
1001                   G_SIGNAL_RUN_LAST,
1002                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1003                   NULL, NULL,
1004                   _gtk_marshal_VOID__VOID,
1005                   G_TYPE_NONE, 0);
1006
1007   /**
1008    * GtkTreeView::cursor-changed:
1009    * @tree_view: the object on which the signal is emitted
1010    * 
1011    * The position of the cursor (focused cell) has changed.
1012    */
1013   tree_view_signals[CURSOR_CHANGED] =
1014     g_signal_new (I_("cursor-changed"),
1015                   G_TYPE_FROM_CLASS (o_class),
1016                   G_SIGNAL_RUN_LAST,
1017                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1018                   NULL, NULL,
1019                   _gtk_marshal_VOID__VOID,
1020                   G_TYPE_NONE, 0);
1021
1022   tree_view_signals[MOVE_CURSOR] =
1023     g_signal_new (I_("move-cursor"),
1024                   G_TYPE_FROM_CLASS (object_class),
1025                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1026                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1027                   NULL, NULL,
1028                   _gtk_marshal_BOOLEAN__ENUM_INT,
1029                   G_TYPE_BOOLEAN, 2,
1030                   GTK_TYPE_MOVEMENT_STEP,
1031                   G_TYPE_INT);
1032
1033   tree_view_signals[SELECT_ALL] =
1034     g_signal_new (I_("select-all"),
1035                   G_TYPE_FROM_CLASS (object_class),
1036                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1037                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1038                   NULL, NULL,
1039                   _gtk_marshal_BOOLEAN__VOID,
1040                   G_TYPE_BOOLEAN, 0);
1041
1042   tree_view_signals[UNSELECT_ALL] =
1043     g_signal_new (I_("unselect-all"),
1044                   G_TYPE_FROM_CLASS (object_class),
1045                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1046                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1047                   NULL, NULL,
1048                   _gtk_marshal_BOOLEAN__VOID,
1049                   G_TYPE_BOOLEAN, 0);
1050
1051   tree_view_signals[SELECT_CURSOR_ROW] =
1052     g_signal_new (I_("select-cursor-row"),
1053                   G_TYPE_FROM_CLASS (object_class),
1054                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1055                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1056                   NULL, NULL,
1057                   _gtk_marshal_BOOLEAN__BOOLEAN,
1058                   G_TYPE_BOOLEAN, 1,
1059                   G_TYPE_BOOLEAN);
1060
1061   tree_view_signals[TOGGLE_CURSOR_ROW] =
1062     g_signal_new (I_("toggle-cursor-row"),
1063                   G_TYPE_FROM_CLASS (object_class),
1064                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1065                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1066                   NULL, NULL,
1067                   _gtk_marshal_BOOLEAN__VOID,
1068                   G_TYPE_BOOLEAN, 0);
1069
1070   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1071     g_signal_new (I_("expand-collapse-cursor-row"),
1072                   G_TYPE_FROM_CLASS (object_class),
1073                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1074                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1075                   NULL, NULL,
1076                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1077                   G_TYPE_BOOLEAN, 3,
1078                   G_TYPE_BOOLEAN,
1079                   G_TYPE_BOOLEAN,
1080                   G_TYPE_BOOLEAN);
1081
1082   tree_view_signals[SELECT_CURSOR_PARENT] =
1083     g_signal_new (I_("select-cursor-parent"),
1084                   G_TYPE_FROM_CLASS (object_class),
1085                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1086                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1087                   NULL, NULL,
1088                   _gtk_marshal_BOOLEAN__VOID,
1089                   G_TYPE_BOOLEAN, 0);
1090
1091   tree_view_signals[START_INTERACTIVE_SEARCH] =
1092     g_signal_new (I_("start-interactive-search"),
1093                   G_TYPE_FROM_CLASS (object_class),
1094                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1095                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1096                   NULL, NULL,
1097                   _gtk_marshal_BOOLEAN__VOID,
1098                   G_TYPE_BOOLEAN, 0);
1099
1100   /* Key bindings */
1101   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1102                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1103   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1104                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1105
1106   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1107                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1108   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1109                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1110
1111   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1112                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1113
1114   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1115                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1116
1117   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1118                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1119   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1120                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1121
1122   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1123                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1124   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1125                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1126
1127   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1128                                   GTK_MOVEMENT_PAGES, -1);
1129   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1130                                   GTK_MOVEMENT_PAGES, -1);
1131
1132   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1133                                   GTK_MOVEMENT_PAGES, 1);
1134   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1135                                   GTK_MOVEMENT_PAGES, 1);
1136
1137
1138   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1139                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1140                                 G_TYPE_INT, 1);
1141
1142   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1143                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1144                                 G_TYPE_INT, -1);
1145
1146   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1147                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1148                                 G_TYPE_INT, 1);
1149
1150   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "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_Right, 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_Left, 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_Right, 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_KP_Left, GDK_CONTROL_MASK,
1170                                 "move-cursor", 2,
1171                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1172                                 G_TYPE_INT, -1);
1173
1174   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1175   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1176
1177   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1178   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1179
1180   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1181   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1182
1183   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1184                                 G_TYPE_BOOLEAN, TRUE);
1185   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1186                                 G_TYPE_BOOLEAN, TRUE);
1187
1188   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1189                                 G_TYPE_BOOLEAN, TRUE);
1190   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1191                                 G_TYPE_BOOLEAN, TRUE);
1192   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1193                                 G_TYPE_BOOLEAN, TRUE);
1194   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1195                                 G_TYPE_BOOLEAN, TRUE);
1196   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198
1199   /* expand and collapse rows */
1200   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1201                                 G_TYPE_BOOLEAN, TRUE,
1202                                 G_TYPE_BOOLEAN, TRUE,
1203                                 G_TYPE_BOOLEAN, FALSE);
1204
1205   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1206                                 "expand-collapse-cursor-row", 3,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE,
1209                                 G_TYPE_BOOLEAN, TRUE);
1210   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1211                                 "expand-collapse-cursor-row", 3,
1212                                 G_TYPE_BOOLEAN, TRUE,
1213                                 G_TYPE_BOOLEAN, TRUE,
1214                                 G_TYPE_BOOLEAN, TRUE);
1215
1216   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1217                                 "expand-collapse-cursor-row", 3,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, FALSE,
1220                                 G_TYPE_BOOLEAN, FALSE);
1221   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1222                                 "expand-collapse-cursor-row", 3,
1223                                 G_TYPE_BOOLEAN, TRUE,
1224                                 G_TYPE_BOOLEAN, FALSE,
1225                                 G_TYPE_BOOLEAN, FALSE);
1226
1227   /* Not doable on US keyboards */
1228   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, TRUE,
1231                                 G_TYPE_BOOLEAN, TRUE);
1232   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1233                                 G_TYPE_BOOLEAN, TRUE,
1234                                 G_TYPE_BOOLEAN, TRUE,
1235                                 G_TYPE_BOOLEAN, FALSE);
1236   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1237                                 G_TYPE_BOOLEAN, TRUE,
1238                                 G_TYPE_BOOLEAN, TRUE,
1239                                 G_TYPE_BOOLEAN, TRUE);
1240   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1241                                 G_TYPE_BOOLEAN, TRUE,
1242                                 G_TYPE_BOOLEAN, TRUE,
1243                                 G_TYPE_BOOLEAN, TRUE);
1244   gtk_binding_entry_add_signal (binding_set, GDK_KEY_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_KP_Right, GDK_SHIFT_MASK,
1250                                 "expand-collapse-cursor-row", 3,
1251                                 G_TYPE_BOOLEAN, FALSE,
1252                                 G_TYPE_BOOLEAN, TRUE,
1253                                 G_TYPE_BOOLEAN, TRUE);
1254   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1255                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1256                                 "expand-collapse-cursor-row", 3,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, TRUE,
1259                                 G_TYPE_BOOLEAN, TRUE);
1260   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1261                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1262                                 "expand-collapse-cursor-row", 3,
1263                                 G_TYPE_BOOLEAN, FALSE,
1264                                 G_TYPE_BOOLEAN, TRUE,
1265                                 G_TYPE_BOOLEAN, TRUE);
1266
1267   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1268                                 G_TYPE_BOOLEAN, TRUE,
1269                                 G_TYPE_BOOLEAN, FALSE,
1270                                 G_TYPE_BOOLEAN, FALSE);
1271   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1272                                 G_TYPE_BOOLEAN, TRUE,
1273                                 G_TYPE_BOOLEAN, FALSE,
1274                                 G_TYPE_BOOLEAN, TRUE);
1275   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1276                                 G_TYPE_BOOLEAN, TRUE,
1277                                 G_TYPE_BOOLEAN, FALSE,
1278                                 G_TYPE_BOOLEAN, FALSE);
1279   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1280                                 G_TYPE_BOOLEAN, TRUE,
1281                                 G_TYPE_BOOLEAN, FALSE,
1282                                 G_TYPE_BOOLEAN, TRUE);
1283   gtk_binding_entry_add_signal (binding_set, GDK_KEY_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_KP_Left, GDK_SHIFT_MASK,
1289                                 "expand-collapse-cursor-row", 3,
1290                                 G_TYPE_BOOLEAN, FALSE,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, TRUE);
1293   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1294                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1295                                 "expand-collapse-cursor-row", 3,
1296                                 G_TYPE_BOOLEAN, FALSE,
1297                                 G_TYPE_BOOLEAN, FALSE,
1298                                 G_TYPE_BOOLEAN, TRUE);
1299   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1300                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1301                                 "expand-collapse-cursor-row", 3,
1302                                 G_TYPE_BOOLEAN, FALSE,
1303                                 G_TYPE_BOOLEAN, FALSE,
1304                                 G_TYPE_BOOLEAN, TRUE);
1305
1306   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1307   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1308
1309   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1310
1311   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1312
1313   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1314 }
1315
1316 static void
1317 gtk_tree_view_init (GtkTreeView *tree_view)
1318 {
1319   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1320
1321   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1322   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1323
1324   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1325                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1326                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1327
1328   /* We need some padding */
1329   tree_view->priv->dy = 0;
1330   tree_view->priv->cursor_offset = 0;
1331   tree_view->priv->n_columns = 0;
1332   tree_view->priv->header_height = 1;
1333   tree_view->priv->x_drag = 0;
1334   tree_view->priv->drag_pos = -1;
1335   tree_view->priv->header_has_focus = FALSE;
1336   tree_view->priv->pressed_button = -1;
1337   tree_view->priv->press_start_x = -1;
1338   tree_view->priv->press_start_y = -1;
1339   tree_view->priv->reorderable = FALSE;
1340   tree_view->priv->presize_handler_timer = 0;
1341   tree_view->priv->scroll_sync_timer = 0;
1342   tree_view->priv->fixed_height = -1;
1343   tree_view->priv->fixed_height_mode = FALSE;
1344   tree_view->priv->fixed_height_check = 0;
1345   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1346   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1347   tree_view->priv->enable_search = TRUE;
1348   tree_view->priv->search_column = -1;
1349   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1350   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1351   tree_view->priv->search_custom_entry_set = FALSE;
1352   tree_view->priv->typeselect_flush_timeout = 0;
1353   tree_view->priv->init_hadjust_value = TRUE;    
1354   tree_view->priv->width = 0;
1355           
1356   tree_view->priv->hover_selection = FALSE;
1357   tree_view->priv->hover_expand = FALSE;
1358
1359   tree_view->priv->level_indentation = 0;
1360
1361   tree_view->priv->rubber_banding_enable = FALSE;
1362
1363   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1364   tree_view->priv->tree_lines_enabled = FALSE;
1365
1366   tree_view->priv->tooltip_column = -1;
1367
1368   tree_view->priv->post_validation_flag = FALSE;
1369
1370   tree_view->priv->last_button_x = -1;
1371   tree_view->priv->last_button_y = -1;
1372
1373   tree_view->priv->event_last_x = -10000;
1374   tree_view->priv->event_last_y = -10000;
1375 }
1376
1377 \f
1378
1379 /* GObject Methods
1380  */
1381
1382 static void
1383 gtk_tree_view_set_property (GObject         *object,
1384                             guint            prop_id,
1385                             const GValue    *value,
1386                             GParamSpec      *pspec)
1387 {
1388   GtkTreeView *tree_view;
1389
1390   tree_view = GTK_TREE_VIEW (object);
1391
1392   switch (prop_id)
1393     {
1394     case PROP_MODEL:
1395       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1396       break;
1397     case PROP_HADJUSTMENT:
1398       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1399       break;
1400     case PROP_VADJUSTMENT:
1401       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1402       break;
1403     case PROP_HEADERS_VISIBLE:
1404       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1405       break;
1406     case PROP_HEADERS_CLICKABLE:
1407       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1408       break;
1409     case PROP_EXPANDER_COLUMN:
1410       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1411       break;
1412     case PROP_REORDERABLE:
1413       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1414       break;
1415     case PROP_RULES_HINT:
1416       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1417       break;
1418     case PROP_ENABLE_SEARCH:
1419       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1420       break;
1421     case PROP_SEARCH_COLUMN:
1422       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1423       break;
1424     case PROP_FIXED_HEIGHT_MODE:
1425       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1426       break;
1427     case PROP_HOVER_SELECTION:
1428       tree_view->priv->hover_selection = g_value_get_boolean (value);
1429       break;
1430     case PROP_HOVER_EXPAND:
1431       tree_view->priv->hover_expand = g_value_get_boolean (value);
1432       break;
1433     case PROP_SHOW_EXPANDERS:
1434       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1435       break;
1436     case PROP_LEVEL_INDENTATION:
1437       tree_view->priv->level_indentation = g_value_get_int (value);
1438       break;
1439     case PROP_RUBBER_BANDING:
1440       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1441       break;
1442     case PROP_ENABLE_GRID_LINES:
1443       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1444       break;
1445     case PROP_ENABLE_TREE_LINES:
1446       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1447       break;
1448     case PROP_TOOLTIP_COLUMN:
1449       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1450       break;
1451     default:
1452       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1453       break;
1454     }
1455 }
1456
1457 static void
1458 gtk_tree_view_get_property (GObject    *object,
1459                             guint       prop_id,
1460                             GValue     *value,
1461                             GParamSpec *pspec)
1462 {
1463   GtkTreeView *tree_view;
1464
1465   tree_view = GTK_TREE_VIEW (object);
1466
1467   switch (prop_id)
1468     {
1469     case PROP_MODEL:
1470       g_value_set_object (value, tree_view->priv->model);
1471       break;
1472     case PROP_HADJUSTMENT:
1473       g_value_set_object (value, tree_view->priv->hadjustment);
1474       break;
1475     case PROP_VADJUSTMENT:
1476       g_value_set_object (value, tree_view->priv->vadjustment);
1477       break;
1478     case PROP_HEADERS_VISIBLE:
1479       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1480       break;
1481     case PROP_HEADERS_CLICKABLE:
1482       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1483       break;
1484     case PROP_EXPANDER_COLUMN:
1485       g_value_set_object (value, tree_view->priv->expander_column);
1486       break;
1487     case PROP_REORDERABLE:
1488       g_value_set_boolean (value, tree_view->priv->reorderable);
1489       break;
1490     case PROP_RULES_HINT:
1491       g_value_set_boolean (value, tree_view->priv->has_rules);
1492       break;
1493     case PROP_ENABLE_SEARCH:
1494       g_value_set_boolean (value, tree_view->priv->enable_search);
1495       break;
1496     case PROP_SEARCH_COLUMN:
1497       g_value_set_int (value, tree_view->priv->search_column);
1498       break;
1499     case PROP_FIXED_HEIGHT_MODE:
1500       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1501       break;
1502     case PROP_HOVER_SELECTION:
1503       g_value_set_boolean (value, tree_view->priv->hover_selection);
1504       break;
1505     case PROP_HOVER_EXPAND:
1506       g_value_set_boolean (value, tree_view->priv->hover_expand);
1507       break;
1508     case PROP_SHOW_EXPANDERS:
1509       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1510       break;
1511     case PROP_LEVEL_INDENTATION:
1512       g_value_set_int (value, tree_view->priv->level_indentation);
1513       break;
1514     case PROP_RUBBER_BANDING:
1515       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1516       break;
1517     case PROP_ENABLE_GRID_LINES:
1518       g_value_set_enum (value, tree_view->priv->grid_lines);
1519       break;
1520     case PROP_ENABLE_TREE_LINES:
1521       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1522       break;
1523     case PROP_TOOLTIP_COLUMN:
1524       g_value_set_int (value, tree_view->priv->tooltip_column);
1525       break;
1526     default:
1527       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1528       break;
1529     }
1530 }
1531
1532 static void
1533 gtk_tree_view_finalize (GObject *object)
1534 {
1535   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1536 }
1537
1538
1539 static GtkBuildableIface *parent_buildable_iface;
1540
1541 static void
1542 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1543 {
1544   parent_buildable_iface = g_type_interface_peek_parent (iface);
1545   iface->add_child = gtk_tree_view_buildable_add_child;
1546   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1547 }
1548
1549 static void
1550 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1551                                    GtkBuilder  *builder,
1552                                    GObject     *child,
1553                                    const gchar *type)
1554 {
1555   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1556 }
1557
1558 static GObject *
1559 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1560                                             GtkBuilder        *builder,
1561                                             const gchar       *childname)
1562 {
1563     if (strcmp (childname, "selection") == 0)
1564       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1565     
1566     return parent_buildable_iface->get_internal_child (buildable,
1567                                                        builder,
1568                                                        childname);
1569 }
1570
1571 /* GtkObject Methods
1572  */
1573
1574 static void
1575 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1576 {
1577   _gtk_rbtree_free (tree_view->priv->tree);
1578   
1579   tree_view->priv->tree = NULL;
1580   tree_view->priv->button_pressed_node = NULL;
1581   tree_view->priv->button_pressed_tree = NULL;
1582   tree_view->priv->prelight_tree = NULL;
1583   tree_view->priv->prelight_node = NULL;
1584   tree_view->priv->expanded_collapsed_node = NULL;
1585   tree_view->priv->expanded_collapsed_tree = NULL;
1586 }
1587
1588 static void
1589 gtk_tree_view_destroy (GtkObject *object)
1590 {
1591   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1592   GList *list;
1593
1594   gtk_tree_view_stop_editing (tree_view, TRUE);
1595
1596   if (tree_view->priv->columns != NULL)
1597     {
1598       list = tree_view->priv->columns;
1599       while (list)
1600         {
1601           GtkTreeViewColumn *column;
1602           column = GTK_TREE_VIEW_COLUMN (list->data);
1603           list = list->next;
1604           gtk_tree_view_remove_column (tree_view, column);
1605         }
1606       tree_view->priv->columns = NULL;
1607     }
1608
1609   if (tree_view->priv->tree != NULL)
1610     {
1611       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1612
1613       gtk_tree_view_free_rbtree (tree_view);
1614     }
1615
1616   if (tree_view->priv->selection != NULL)
1617     {
1618       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1619       g_object_unref (tree_view->priv->selection);
1620       tree_view->priv->selection = NULL;
1621     }
1622
1623   if (tree_view->priv->scroll_to_path != NULL)
1624     {
1625       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1626       tree_view->priv->scroll_to_path = NULL;
1627     }
1628
1629   if (tree_view->priv->drag_dest_row != NULL)
1630     {
1631       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1632       tree_view->priv->drag_dest_row = NULL;
1633     }
1634
1635   if (tree_view->priv->top_row != NULL)
1636     {
1637       gtk_tree_row_reference_free (tree_view->priv->top_row);
1638       tree_view->priv->top_row = NULL;
1639     }
1640
1641   if (tree_view->priv->column_drop_func_data &&
1642       tree_view->priv->column_drop_func_data_destroy)
1643     {
1644       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1645       tree_view->priv->column_drop_func_data = NULL;
1646     }
1647
1648   if (tree_view->priv->destroy_count_destroy &&
1649       tree_view->priv->destroy_count_data)
1650     {
1651       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1652       tree_view->priv->destroy_count_data = NULL;
1653     }
1654
1655   gtk_tree_row_reference_free (tree_view->priv->cursor);
1656   tree_view->priv->cursor = NULL;
1657
1658   gtk_tree_row_reference_free (tree_view->priv->anchor);
1659   tree_view->priv->anchor = NULL;
1660
1661   /* destroy interactive search dialog */
1662   if (tree_view->priv->search_window)
1663     {
1664       gtk_widget_destroy (tree_view->priv->search_window);
1665       tree_view->priv->search_window = NULL;
1666       tree_view->priv->search_entry = NULL;
1667       if (tree_view->priv->typeselect_flush_timeout)
1668         {
1669           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1670           tree_view->priv->typeselect_flush_timeout = 0;
1671         }
1672     }
1673
1674   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1675     {
1676       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1677       tree_view->priv->search_user_data = NULL;
1678     }
1679
1680   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1681     {
1682       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1683       tree_view->priv->search_position_user_data = NULL;
1684     }
1685
1686   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1687     {
1688       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1689       tree_view->priv->row_separator_data = NULL;
1690     }
1691   
1692   gtk_tree_view_set_model (tree_view, NULL);
1693
1694   if (tree_view->priv->hadjustment)
1695     {
1696       g_object_unref (tree_view->priv->hadjustment);
1697       tree_view->priv->hadjustment = NULL;
1698     }
1699   if (tree_view->priv->vadjustment)
1700     {
1701       g_object_unref (tree_view->priv->vadjustment);
1702       tree_view->priv->vadjustment = NULL;
1703     }
1704
1705   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1706 }
1707
1708 \f
1709
1710 /* GtkWidget Methods
1711  */
1712
1713 /* GtkWidget::map helper */
1714 static void
1715 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1716 {
1717   GList *list;
1718
1719   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1720
1721   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1722     {
1723       GtkTreeViewColumn *column;
1724
1725       for (list = tree_view->priv->columns; list; list = list->next)
1726         {
1727           column = list->data;
1728           if (gtk_widget_get_visible (column->button) &&
1729               !gtk_widget_get_mapped (column->button))
1730             gtk_widget_map (column->button);
1731         }
1732       for (list = tree_view->priv->columns; list; list = list->next)
1733         {
1734           column = list->data;
1735           if (column->visible == FALSE)
1736             continue;
1737           if (column->resizable)
1738             {
1739               gdk_window_raise (column->window);
1740               gdk_window_show (column->window);
1741             }
1742           else
1743             gdk_window_hide (column->window);
1744         }
1745       gdk_window_show (tree_view->priv->header_window);
1746     }
1747 }
1748
1749 static void
1750 gtk_tree_view_map (GtkWidget *widget)
1751 {
1752   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1753   GList *tmp_list;
1754
1755   gtk_widget_set_mapped (widget, TRUE);
1756
1757   tmp_list = tree_view->priv->children;
1758   while (tmp_list)
1759     {
1760       GtkTreeViewChild *child = tmp_list->data;
1761       tmp_list = tmp_list->next;
1762
1763       if (gtk_widget_get_visible (child->widget))
1764         {
1765           if (!gtk_widget_get_mapped (child->widget))
1766             gtk_widget_map (child->widget);
1767         }
1768     }
1769   gdk_window_show (tree_view->priv->bin_window);
1770
1771   gtk_tree_view_map_buttons (tree_view);
1772
1773   gdk_window_show (gtk_widget_get_window (widget));
1774 }
1775
1776 static void
1777 gtk_tree_view_realize (GtkWidget *widget)
1778 {
1779   GtkAllocation allocation;
1780   GtkStyle *style;
1781   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1782   GdkWindow *window;
1783   GdkWindowAttr attributes;
1784   GList *tmp_list;
1785   gint attributes_mask;
1786
1787   gtk_widget_set_realized (widget, TRUE);
1788
1789   gtk_widget_get_allocation (widget, &allocation);
1790
1791   /* Make the main, clipping window */
1792   attributes.window_type = GDK_WINDOW_CHILD;
1793   attributes.x = allocation.x;
1794   attributes.y = allocation.y;
1795   attributes.width = allocation.width;
1796   attributes.height = allocation.height;
1797   attributes.wclass = GDK_INPUT_OUTPUT;
1798   attributes.visual = gtk_widget_get_visual (widget);
1799   attributes.colormap = gtk_widget_get_colormap (widget);
1800   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1801
1802   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1803
1804   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1805                            &attributes, attributes_mask);
1806   gtk_widget_set_window (widget, window);
1807   gdk_window_set_user_data (window, widget);
1808
1809   gtk_widget_get_allocation (widget, &allocation);
1810
1811   /* Make the window for the tree */
1812   attributes.x = 0;
1813   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1814   attributes.width = MAX (tree_view->priv->width, allocation.width);
1815   attributes.height = allocation.height;
1816   attributes.event_mask = (GDK_EXPOSURE_MASK |
1817                            GDK_SCROLL_MASK |
1818                            GDK_POINTER_MOTION_MASK |
1819                            GDK_ENTER_NOTIFY_MASK |
1820                            GDK_LEAVE_NOTIFY_MASK |
1821                            GDK_BUTTON_PRESS_MASK |
1822                            GDK_BUTTON_RELEASE_MASK |
1823                            gtk_widget_get_events (widget));
1824
1825   tree_view->priv->bin_window = gdk_window_new (window,
1826                                                 &attributes, attributes_mask);
1827   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1828
1829   gtk_widget_get_allocation (widget, &allocation);
1830
1831   /* Make the column header window */
1832   attributes.x = 0;
1833   attributes.y = 0;
1834   attributes.width = MAX (tree_view->priv->width, allocation.width);
1835   attributes.height = tree_view->priv->header_height;
1836   attributes.event_mask = (GDK_EXPOSURE_MASK |
1837                            GDK_SCROLL_MASK |
1838                            GDK_ENTER_NOTIFY_MASK |
1839                            GDK_LEAVE_NOTIFY_MASK |
1840                            GDK_BUTTON_PRESS_MASK |
1841                            GDK_BUTTON_RELEASE_MASK |
1842                            GDK_KEY_PRESS_MASK |
1843                            GDK_KEY_RELEASE_MASK |
1844                            gtk_widget_get_events (widget));
1845
1846   tree_view->priv->header_window = gdk_window_new (window,
1847                                                    &attributes, attributes_mask);
1848   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1849
1850   /* Add them all up. */
1851   gtk_widget_style_attach (widget);
1852   gdk_window_set_back_pixmap (window, NULL, FALSE);
1853   style = gtk_widget_get_style (widget);
1854   gdk_window_set_background (tree_view->priv->bin_window,
1855                              &style->base[gtk_widget_get_state (widget)]);
1856   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1857
1858   tmp_list = tree_view->priv->children;
1859   while (tmp_list)
1860     {
1861       GtkTreeViewChild *child = tmp_list->data;
1862       tmp_list = tmp_list->next;
1863
1864       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1865     }
1866
1867   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1868     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1869
1870   /* Need to call those here, since they create GCs */
1871   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1872   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1873
1874   install_presize_handler (tree_view); 
1875 }
1876
1877 static void
1878 gtk_tree_view_unrealize (GtkWidget *widget)
1879 {
1880   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1881   GtkTreeViewPrivate *priv = tree_view->priv;
1882   GList *list;
1883
1884   if (priv->scroll_timeout != 0)
1885     {
1886       g_source_remove (priv->scroll_timeout);
1887       priv->scroll_timeout = 0;
1888     }
1889
1890   if (priv->auto_expand_timeout != 0)
1891     {
1892       g_source_remove (priv->auto_expand_timeout);
1893       priv->auto_expand_timeout = 0;
1894     }
1895
1896   if (priv->open_dest_timeout != 0)
1897     {
1898       g_source_remove (priv->open_dest_timeout);
1899       priv->open_dest_timeout = 0;
1900     }
1901
1902   remove_expand_collapse_timeout (tree_view);
1903   
1904   if (priv->presize_handler_timer != 0)
1905     {
1906       g_source_remove (priv->presize_handler_timer);
1907       priv->presize_handler_timer = 0;
1908     }
1909
1910   if (priv->validate_rows_timer != 0)
1911     {
1912       g_source_remove (priv->validate_rows_timer);
1913       priv->validate_rows_timer = 0;
1914     }
1915
1916   if (priv->scroll_sync_timer != 0)
1917     {
1918       g_source_remove (priv->scroll_sync_timer);
1919       priv->scroll_sync_timer = 0;
1920     }
1921
1922   if (priv->typeselect_flush_timeout)
1923     {
1924       g_source_remove (priv->typeselect_flush_timeout);
1925       priv->typeselect_flush_timeout = 0;
1926     }
1927   
1928   for (list = priv->columns; list; list = list->next)
1929     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1930
1931   gdk_window_set_user_data (priv->bin_window, NULL);
1932   gdk_window_destroy (priv->bin_window);
1933   priv->bin_window = NULL;
1934
1935   gdk_window_set_user_data (priv->header_window, NULL);
1936   gdk_window_destroy (priv->header_window);
1937   priv->header_window = NULL;
1938
1939   if (priv->drag_window)
1940     {
1941       gdk_window_set_user_data (priv->drag_window, NULL);
1942       gdk_window_destroy (priv->drag_window);
1943       priv->drag_window = NULL;
1944     }
1945
1946   if (priv->drag_highlight_window)
1947     {
1948       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1949       gdk_window_destroy (priv->drag_highlight_window);
1950       priv->drag_highlight_window = NULL;
1951     }
1952
1953   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1954 }
1955
1956 /* GtkWidget::size_request helper */
1957 static void
1958 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1959 {
1960   GList *list;
1961
1962   tree_view->priv->header_height = 0;
1963
1964   if (tree_view->priv->model)
1965     {
1966       for (list = tree_view->priv->columns; list; list = list->next)
1967         {
1968           GtkRequisition requisition;
1969           GtkTreeViewColumn *column = list->data;
1970
1971           if (column->button == NULL)
1972             continue;
1973
1974           column = list->data;
1975
1976           gtk_size_request_get_size (GTK_SIZE_REQUEST (column->button),
1977                                      &requisition, NULL);
1978           column->button_request = requisition.width;
1979           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1980         }
1981     }
1982 }
1983
1984
1985 /* Called only by ::size_request */
1986 static void
1987 gtk_tree_view_update_size (GtkTreeView *tree_view)
1988 {
1989   GList *list;
1990   GtkTreeViewColumn *column;
1991   gint i;
1992
1993   if (tree_view->priv->model == NULL)
1994     {
1995       tree_view->priv->width = 0;
1996       tree_view->priv->prev_width = 0;                   
1997       tree_view->priv->height = 0;
1998       return;
1999     }
2000
2001   tree_view->priv->prev_width = tree_view->priv->width;  
2002   tree_view->priv->width = 0;
2003
2004   /* keep this in sync with size_allocate below */
2005   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2006     {
2007       gint real_requested_width = 0;
2008       column = list->data;
2009       if (!column->visible)
2010         continue;
2011
2012       if (column->use_resized_width)
2013         {
2014           real_requested_width = column->resized_width;
2015         }
2016       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2017         {
2018           real_requested_width = column->fixed_width;
2019         }
2020       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2021         {
2022           real_requested_width = MAX (column->requested_width, column->button_request);
2023         }
2024       else
2025         {
2026           real_requested_width = column->requested_width;
2027         }
2028
2029       if (column->min_width != -1)
2030         real_requested_width = MAX (real_requested_width, column->min_width);
2031       if (column->max_width != -1)
2032         real_requested_width = MIN (real_requested_width, column->max_width);
2033
2034       tree_view->priv->width += real_requested_width;
2035     }
2036
2037   if (tree_view->priv->tree == NULL)
2038     tree_view->priv->height = 0;
2039   else
2040     tree_view->priv->height = tree_view->priv->tree->root->offset;
2041 }
2042
2043 static void
2044 gtk_tree_view_size_request (GtkWidget      *widget,
2045                             GtkRequisition *requisition)
2046 {
2047   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2048   GList *tmp_list;
2049
2050   /* we validate some rows initially just to make sure we have some size. 
2051    * In practice, with a lot of static lists, this should get a good width.
2052    */
2053   do_validate_rows (tree_view, FALSE);
2054   gtk_tree_view_size_request_columns (tree_view);
2055   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2056
2057   requisition->width = tree_view->priv->width;
2058   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2059
2060   tmp_list = tree_view->priv->children;
2061
2062   while (tmp_list)
2063     {
2064       GtkTreeViewChild *child = tmp_list->data;
2065       GtkRequisition child_requisition;
2066
2067       tmp_list = tmp_list->next;
2068
2069       if (gtk_widget_get_visible (child->widget))
2070         gtk_size_request_get_size (GTK_SIZE_REQUEST (child->widget),
2071                                    &child_requisition, NULL);
2072     }
2073 }
2074
2075 static int
2076 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2077 {
2078   int width = 0;
2079   GList *list;
2080   gboolean rtl;
2081
2082   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2083   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2084        list->data != tree_view->priv->expander_column;
2085        list = (rtl ? list->prev : list->next))
2086     {
2087       GtkTreeViewColumn *column = list->data;
2088
2089       width += column->width;
2090     }
2091
2092   return width;
2093 }
2094
2095 static void
2096 invalidate_column (GtkTreeView       *tree_view,
2097                    GtkTreeViewColumn *column)
2098 {
2099   gint column_offset = 0;
2100   GList *list;
2101   GtkWidget *widget = GTK_WIDGET (tree_view);
2102   gboolean rtl;
2103
2104   if (!gtk_widget_get_realized (widget))
2105     return;
2106
2107   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2108   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2109        list;
2110        list = (rtl ? list->prev : list->next))
2111     {
2112       GtkTreeViewColumn *tmpcolumn = list->data;
2113       if (tmpcolumn == column)
2114         {
2115           GtkAllocation allocation;
2116           GdkRectangle invalid_rect;
2117
2118           gtk_widget_get_allocation (widget, &allocation);
2119           invalid_rect.x = column_offset;
2120           invalid_rect.y = 0;
2121           invalid_rect.width = column->width;
2122           invalid_rect.height = allocation.height;
2123
2124           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2125           break;
2126         }
2127       
2128       column_offset += tmpcolumn->width;
2129     }
2130 }
2131
2132 static void
2133 invalidate_last_column (GtkTreeView *tree_view)
2134 {
2135   GList *last_column;
2136   gboolean rtl;
2137
2138   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2139
2140   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2141        last_column;
2142        last_column = (rtl ? last_column->next : last_column->prev))
2143     {
2144       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2145         {
2146           invalidate_column (tree_view, last_column->data);
2147           return;
2148         }
2149     }
2150 }
2151
2152 static gint
2153 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2154                                                     GtkTreeViewColumn *column)
2155 {
2156   gint real_requested_width;
2157
2158   if (column->use_resized_width)
2159     {
2160       real_requested_width = column->resized_width;
2161     }
2162   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2163     {
2164       real_requested_width = column->fixed_width;
2165     }
2166   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2167     {
2168       real_requested_width = MAX (column->requested_width, column->button_request);
2169     }
2170   else
2171     {
2172       real_requested_width = column->requested_width;
2173       if (real_requested_width < 0)
2174         real_requested_width = 0;
2175     }
2176
2177   if (column->min_width != -1)
2178     real_requested_width = MAX (real_requested_width, column->min_width);
2179   if (column->max_width != -1)
2180     real_requested_width = MIN (real_requested_width, column->max_width);
2181
2182   return real_requested_width;
2183 }
2184
2185 /* GtkWidget::size_allocate helper */
2186 static void
2187 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2188                                      gboolean  *width_changed)
2189 {
2190   GtkTreeView *tree_view;
2191   GList *list, *first_column, *last_column;
2192   GtkTreeViewColumn *column;
2193   GtkAllocation allocation;
2194   GtkAllocation widget_allocation;
2195   gint width = 0;
2196   gint extra, extra_per_column, extra_for_last;
2197   gint full_requested_width = 0;
2198   gint number_of_expand_columns = 0;
2199   gboolean column_changed = FALSE;
2200   gboolean rtl;
2201   gboolean update_expand;
2202   
2203   tree_view = GTK_TREE_VIEW (widget);
2204
2205   for (last_column = g_list_last (tree_view->priv->columns);
2206        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2207        last_column = last_column->prev)
2208     ;
2209   if (last_column == NULL)
2210     return;
2211
2212   for (first_column = g_list_first (tree_view->priv->columns);
2213        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2214        first_column = first_column->next)
2215     ;
2216
2217   allocation.y = 0;
2218   allocation.height = tree_view->priv->header_height;
2219
2220   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2221
2222   /* find out how many extra space and expandable columns we have */
2223   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2224     {
2225       column = (GtkTreeViewColumn *)list->data;
2226
2227       if (!column->visible)
2228         continue;
2229
2230       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2231
2232       if (column->expand)
2233         number_of_expand_columns++;
2234     }
2235
2236   /* Only update the expand value if the width of the widget has changed,
2237    * or the number of expand columns has changed, or if there are no expand
2238    * columns, or if we didn't have an size-allocation yet after the
2239    * last validated node.
2240    */
2241   update_expand = (width_changed && *width_changed == TRUE)
2242       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2243       || number_of_expand_columns == 0
2244       || tree_view->priv->post_validation_flag == TRUE;
2245
2246   tree_view->priv->post_validation_flag = FALSE;
2247
2248   gtk_widget_get_allocation (widget, &widget_allocation);
2249   if (!update_expand)
2250     {
2251       extra = tree_view->priv->last_extra_space;
2252       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2253     }
2254   else
2255     {
2256       extra = MAX (widget_allocation.width - full_requested_width, 0);
2257       extra_for_last = 0;
2258
2259       tree_view->priv->last_extra_space = extra;
2260     }
2261
2262   if (number_of_expand_columns > 0)
2263     extra_per_column = extra/number_of_expand_columns;
2264   else
2265     extra_per_column = 0;
2266
2267   if (update_expand)
2268     {
2269       tree_view->priv->last_extra_space_per_column = extra_per_column;
2270       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2271     }
2272
2273   for (list = (rtl ? last_column : first_column); 
2274        list != (rtl ? first_column->prev : last_column->next);
2275        list = (rtl ? list->prev : list->next)) 
2276     {
2277       gint real_requested_width = 0;
2278       gint old_width;
2279
2280       column = list->data;
2281       old_width = column->width;
2282
2283       if (!column->visible)
2284         continue;
2285
2286       /* We need to handle the dragged button specially.
2287        */
2288       if (column == tree_view->priv->drag_column)
2289         {
2290           GtkAllocation drag_allocation;
2291           gdk_drawable_get_size (tree_view->priv->drag_window,
2292                                  &(drag_allocation.width),
2293                                  &(drag_allocation.height));
2294           drag_allocation.x = 0;
2295           drag_allocation.y = 0;
2296           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2297                                     &drag_allocation);
2298           width += drag_allocation.width;
2299           continue;
2300         }
2301
2302       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2303
2304       allocation.x = width;
2305       column->width = real_requested_width;
2306
2307       if (column->expand)
2308         {
2309           if (number_of_expand_columns == 1)
2310             {
2311               /* We add the remander to the last column as
2312                * */
2313               column->width += extra;
2314             }
2315           else
2316             {
2317               column->width += extra_per_column;
2318               extra -= extra_per_column;
2319               number_of_expand_columns --;
2320             }
2321         }
2322       else if (number_of_expand_columns == 0 &&
2323                list == last_column)
2324         {
2325           column->width += extra;
2326         }
2327
2328       /* In addition to expand, the last column can get even more
2329        * extra space so all available space is filled up.
2330        */
2331       if (extra_for_last > 0 && list == last_column)
2332         column->width += extra_for_last;
2333
2334       g_object_notify (G_OBJECT (column), "width");
2335
2336       allocation.width = column->width;
2337       width += column->width;
2338
2339       if (column->width > old_width)
2340         column_changed = TRUE;
2341
2342       gtk_widget_size_allocate (column->button, &allocation);
2343
2344       if (column->window)
2345         gdk_window_move_resize (column->window,
2346                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2347                                 allocation.y,
2348                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2349     }
2350
2351   /* We change the width here.  The user might have been resizing columns,
2352    * so the total width of the tree view changes.
2353    */
2354   tree_view->priv->width = width;
2355   if (width_changed)
2356     *width_changed = TRUE;
2357
2358   if (column_changed)
2359     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2360 }
2361
2362
2363 static void
2364 gtk_tree_view_size_allocate (GtkWidget     *widget,
2365                              GtkAllocation *allocation)
2366 {
2367   GtkAllocation widget_allocation;
2368   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2369   GList *tmp_list;
2370   gboolean width_changed = FALSE;
2371   gint old_width;
2372
2373   gtk_widget_get_allocation (widget, &widget_allocation);
2374   old_width = widget_allocation.width;
2375   if (allocation->width != widget_allocation.width)
2376     width_changed = TRUE;
2377
2378   gtk_widget_set_allocation (widget, allocation);
2379
2380   tmp_list = tree_view->priv->children;
2381
2382   while (tmp_list)
2383     {
2384       GtkAllocation allocation;
2385
2386       GtkTreeViewChild *child = tmp_list->data;
2387       tmp_list = tmp_list->next;
2388
2389       /* totally ignore our child's requisition */
2390       allocation.x = child->x;
2391       allocation.y = child->y;
2392       allocation.width = child->width;
2393       allocation.height = child->height;
2394       gtk_widget_size_allocate (child->widget, &allocation);
2395     }
2396
2397   /* We size-allocate the columns first because the width of the
2398    * tree view (used in updating the adjustments below) might change.
2399    */
2400   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2401
2402   tree_view->priv->hadjustment->page_size = allocation->width;
2403   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2404   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2405   tree_view->priv->hadjustment->lower = 0;
2406   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2407
2408   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2409     {
2410       if (allocation->width < tree_view->priv->width)
2411         {
2412           if (tree_view->priv->init_hadjust_value)
2413             {
2414               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2415               tree_view->priv->init_hadjust_value = FALSE;
2416             }
2417           else if (allocation->width != old_width)
2418             {
2419               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2420             }
2421           else
2422             tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
2423         }
2424       else
2425         {
2426           tree_view->priv->hadjustment->value = 0;
2427           tree_view->priv->init_hadjust_value = TRUE;
2428         }
2429     }
2430   else
2431     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2432       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2433
2434   gtk_adjustment_changed (tree_view->priv->hadjustment);
2435
2436   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2437   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2438   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2439   tree_view->priv->vadjustment->lower = 0;
2440   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2441
2442   gtk_adjustment_changed (tree_view->priv->vadjustment);
2443
2444   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2445   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2446     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2447   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2448     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2449                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2450   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2451     gtk_tree_view_top_row_to_dy (tree_view);
2452   else
2453     gtk_tree_view_dy_to_top_row (tree_view);
2454   
2455   if (gtk_widget_get_realized (widget))
2456     {
2457       gdk_window_move_resize (gtk_widget_get_window (widget),
2458                               allocation->x, allocation->y,
2459                               allocation->width, allocation->height);
2460       gdk_window_move_resize (tree_view->priv->header_window,
2461                               - (gint) tree_view->priv->hadjustment->value,
2462                               0,
2463                               MAX (tree_view->priv->width, allocation->width),
2464                               tree_view->priv->header_height);
2465       gdk_window_move_resize (tree_view->priv->bin_window,
2466                               - (gint) tree_view->priv->hadjustment->value,
2467                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2468                               MAX (tree_view->priv->width, allocation->width),
2469                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2470     }
2471
2472   if (tree_view->priv->tree == NULL)
2473     invalidate_empty_focus (tree_view);
2474
2475   if (gtk_widget_get_realized (widget))
2476     {
2477       gboolean has_expand_column = FALSE;
2478       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2479         {
2480           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2481             {
2482               has_expand_column = TRUE;
2483               break;
2484             }
2485         }
2486
2487       if (width_changed && tree_view->priv->expander_column)
2488         {
2489           /* Might seem awkward, but is the best heuristic I could come up
2490            * with.  Only if the width of the columns before the expander
2491            * changes, we will update the prelight status.  It is this
2492            * width that makes the expander move vertically.  Always updating
2493            * prelight status causes trouble with hover selections.
2494            */
2495           gint width_before_expander;
2496
2497           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2498
2499           if (tree_view->priv->prev_width_before_expander
2500               != width_before_expander)
2501               update_prelight (tree_view,
2502                                tree_view->priv->event_last_x,
2503                                tree_view->priv->event_last_y);
2504
2505           tree_view->priv->prev_width_before_expander = width_before_expander;
2506         }
2507
2508       /* This little hack only works if we have an LTR locale, and no column has the  */
2509       if (width_changed)
2510         {
2511           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2512               ! has_expand_column)
2513             invalidate_last_column (tree_view);
2514           else
2515             gtk_widget_queue_draw (widget);
2516         }
2517     }
2518 }
2519
2520 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2521 static void
2522 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2523 {
2524   GtkWidget *widget = GTK_WIDGET (tree_view);
2525
2526   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2527     gtk_widget_grab_focus (widget);
2528   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2529 }
2530
2531 static inline gboolean
2532 row_is_separator (GtkTreeView *tree_view,
2533                   GtkTreeIter *iter,
2534                   GtkTreePath *path)
2535 {
2536   gboolean is_separator = FALSE;
2537
2538   if (tree_view->priv->row_separator_func)
2539     {
2540       GtkTreeIter tmpiter;
2541
2542       if (iter)
2543         tmpiter = *iter;
2544       else
2545         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2546
2547       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2548                                                           &tmpiter,
2549                                                           tree_view->priv->row_separator_data);
2550     }
2551
2552   return is_separator;
2553 }
2554
2555 static gboolean
2556 gtk_tree_view_button_press (GtkWidget      *widget,
2557                             GdkEventButton *event)
2558 {
2559   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2560   GList *list;
2561   GtkTreeViewColumn *column = NULL;
2562   gint i;
2563   GdkRectangle background_area;
2564   GdkRectangle cell_area;
2565   gint vertical_separator;
2566   gint horizontal_separator;
2567   gboolean path_is_selectable;
2568   gboolean rtl;
2569
2570   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2571   gtk_tree_view_stop_editing (tree_view, FALSE);
2572   gtk_widget_style_get (widget,
2573                         "vertical-separator", &vertical_separator,
2574                         "horizontal-separator", &horizontal_separator,
2575                         NULL);
2576
2577
2578   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2579    * we're done handling the button press.
2580    */
2581
2582   if (event->window == tree_view->priv->bin_window)
2583     {
2584       GtkRBNode *node;
2585       GtkRBTree *tree;
2586       GtkTreePath *path;
2587       gchar *path_string;
2588       gint depth;
2589       gint new_y;
2590       gint y_offset;
2591       gint dval;
2592       gint pre_val, aft_val;
2593       GtkTreeViewColumn *column = NULL;
2594       GtkCellRenderer *focus_cell = NULL;
2595       gint column_handled_click = FALSE;
2596       gboolean row_double_click = FALSE;
2597       gboolean rtl;
2598       gboolean node_selected;
2599
2600       /* Empty tree? */
2601       if (tree_view->priv->tree == NULL)
2602         {
2603           grab_focus_and_unset_draw_keyfocus (tree_view);
2604           return TRUE;
2605         }
2606
2607       /* are we in an arrow? */
2608       if (tree_view->priv->prelight_node &&
2609           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2610           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2611         {
2612           if (event->button == 1)
2613             {
2614               gtk_grab_add (widget);
2615               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2616               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2617               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2618                                         tree_view->priv->prelight_tree,
2619                                         tree_view->priv->prelight_node,
2620                                         event->x,
2621                                         event->y);
2622             }
2623
2624           grab_focus_and_unset_draw_keyfocus (tree_view);
2625           return TRUE;
2626         }
2627
2628       /* find the node that was clicked */
2629       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2630       if (new_y < 0)
2631         new_y = 0;
2632       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2633
2634       if (node == NULL)
2635         {
2636           /* We clicked in dead space */
2637           grab_focus_and_unset_draw_keyfocus (tree_view);
2638           return TRUE;
2639         }
2640
2641       /* Get the path and the node */
2642       path = _gtk_tree_view_find_path (tree_view, tree, node);
2643       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2644
2645       if (!path_is_selectable)
2646         {
2647           gtk_tree_path_free (path);
2648           grab_focus_and_unset_draw_keyfocus (tree_view);
2649           return TRUE;
2650         }
2651
2652       depth = gtk_tree_path_get_depth (path);
2653       background_area.y = y_offset + event->y;
2654       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2655       background_area.x = 0;
2656
2657
2658       /* Let the column have a chance at selecting it. */
2659       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2660       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2661            list; list = (rtl ? list->prev : list->next))
2662         {
2663           GtkTreeViewColumn *candidate = list->data;
2664
2665           if (!candidate->visible)
2666             continue;
2667
2668           background_area.width = candidate->width;
2669           if ((background_area.x > (gint) event->x) ||
2670               (background_area.x + background_area.width <= (gint) event->x))
2671             {
2672               background_area.x += background_area.width;
2673               continue;
2674             }
2675
2676           /* we found the focus column */
2677           column = candidate;
2678           cell_area = background_area;
2679           cell_area.width -= horizontal_separator;
2680           cell_area.height -= vertical_separator;
2681           cell_area.x += horizontal_separator/2;
2682           cell_area.y += vertical_separator/2;
2683           if (gtk_tree_view_is_expander_column (tree_view, column))
2684             {
2685               if (!rtl)
2686                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2687               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2688
2689               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2690                 {
2691                   if (!rtl)
2692                     cell_area.x += depth * tree_view->priv->expander_size;
2693                   cell_area.width -= depth * tree_view->priv->expander_size;
2694                 }
2695             }
2696           break;
2697         }
2698
2699       if (column == NULL)
2700         {
2701           gtk_tree_path_free (path);
2702           grab_focus_and_unset_draw_keyfocus (tree_view);
2703           return FALSE;
2704         }
2705
2706       tree_view->priv->focus_column = column;
2707
2708       /* decide if we edit */
2709       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2710           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2711         {
2712           GtkTreePath *anchor;
2713           GtkTreeIter iter;
2714
2715           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2716           gtk_tree_view_column_cell_set_cell_data (column,
2717                                                    tree_view->priv->model,
2718                                                    &iter,
2719                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2720                                                    node->children?TRUE:FALSE);
2721
2722           if (tree_view->priv->anchor)
2723             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2724           else
2725             anchor = NULL;
2726
2727           if ((anchor && !gtk_tree_path_compare (anchor, path))
2728               || !_gtk_tree_view_column_has_editable_cell (column))
2729             {
2730               GtkCellEditable *cell_editable = NULL;
2731
2732               /* FIXME: get the right flags */
2733               guint flags = 0;
2734
2735               path_string = gtk_tree_path_to_string (path);
2736
2737               if (_gtk_tree_view_column_cell_event (column,
2738                                                     &cell_editable,
2739                                                     (GdkEvent *)event,
2740                                                     path_string,
2741                                                     &background_area,
2742                                                     &cell_area, flags))
2743                 {
2744                   if (cell_editable != NULL)
2745                     {
2746                       gint left, right;
2747                       GdkRectangle area;
2748
2749                       area = cell_area;
2750                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2751
2752                       area.x += left;
2753                       area.width -= right + left;
2754
2755                       gtk_tree_view_real_start_editing (tree_view,
2756                                                         column,
2757                                                         path,
2758                                                         cell_editable,
2759                                                         &area,
2760                                                         (GdkEvent *)event,
2761                                                         flags);
2762                       g_free (path_string);
2763                       gtk_tree_path_free (path);
2764                       gtk_tree_path_free (anchor);
2765                       return TRUE;
2766                     }
2767                   column_handled_click = TRUE;
2768                 }
2769               g_free (path_string);
2770             }
2771           if (anchor)
2772             gtk_tree_path_free (anchor);
2773         }
2774
2775       /* select */
2776       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2777       pre_val = tree_view->priv->vadjustment->value;
2778
2779       /* we only handle selection modifications on the first button press
2780        */
2781       if (event->type == GDK_BUTTON_PRESS)
2782         {
2783           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2784             tree_view->priv->ctrl_pressed = TRUE;
2785           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2786             tree_view->priv->shift_pressed = TRUE;
2787
2788           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2789           if (focus_cell)
2790             gtk_tree_view_column_focus_cell (column, focus_cell);
2791
2792           if (event->state & GDK_CONTROL_MASK)
2793             {
2794               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2795               gtk_tree_view_real_toggle_cursor_row (tree_view);
2796             }
2797           else if (event->state & GDK_SHIFT_MASK)
2798             {
2799               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2800               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2801             }
2802           else
2803             {
2804               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2805             }
2806
2807           tree_view->priv->ctrl_pressed = FALSE;
2808           tree_view->priv->shift_pressed = FALSE;
2809         }
2810
2811       /* the treeview may have been scrolled because of _set_cursor,
2812        * correct here
2813        */
2814
2815       aft_val = tree_view->priv->vadjustment->value;
2816       dval = pre_val - aft_val;
2817
2818       cell_area.y += dval;
2819       background_area.y += dval;
2820
2821       /* Save press to possibly begin a drag
2822        */
2823       if (!column_handled_click &&
2824           !tree_view->priv->in_grab &&
2825           tree_view->priv->pressed_button < 0)
2826         {
2827           tree_view->priv->pressed_button = event->button;
2828           tree_view->priv->press_start_x = event->x;
2829           tree_view->priv->press_start_y = event->y;
2830
2831           if (tree_view->priv->rubber_banding_enable
2832               && !node_selected
2833               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2834             {
2835               tree_view->priv->press_start_y += tree_view->priv->dy;
2836               tree_view->priv->rubber_band_x = event->x;
2837               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2838               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2839
2840               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2841                 tree_view->priv->rubber_band_ctrl = TRUE;
2842               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2843                 tree_view->priv->rubber_band_shift = TRUE;
2844             }
2845         }
2846
2847       /* Test if a double click happened on the same row. */
2848       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2849         {
2850           int double_click_time, double_click_distance;
2851
2852           g_object_get (gtk_settings_get_default (),
2853                         "gtk-double-click-time", &double_click_time,
2854                         "gtk-double-click-distance", &double_click_distance,
2855                         NULL);
2856
2857           /* Same conditions as _gdk_event_button_generate */
2858           if (tree_view->priv->last_button_x != -1 &&
2859               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2860               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2861               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2862             {
2863               /* We do no longer compare paths of this row and the
2864                * row clicked previously.  We use the double click
2865                * distance to decide whether this is a valid click,
2866                * allowing the mouse to slightly move over another row.
2867                */
2868               row_double_click = TRUE;
2869
2870               tree_view->priv->last_button_time = 0;
2871               tree_view->priv->last_button_x = -1;
2872               tree_view->priv->last_button_y = -1;
2873             }
2874           else
2875             {
2876               tree_view->priv->last_button_time = event->time;
2877               tree_view->priv->last_button_x = event->x;
2878               tree_view->priv->last_button_y = event->y;
2879             }
2880         }
2881
2882       if (row_double_click)
2883         {
2884           gtk_grab_remove (widget);
2885           gtk_tree_view_row_activated (tree_view, path, column);
2886
2887           if (tree_view->priv->pressed_button == event->button)
2888             tree_view->priv->pressed_button = -1;
2889         }
2890
2891       gtk_tree_path_free (path);
2892
2893       /* If we activated the row through a double click we don't want to grab
2894        * focus back, as moving focus to another widget is pretty common.
2895        */
2896       if (!row_double_click)
2897         grab_focus_and_unset_draw_keyfocus (tree_view);
2898
2899       return TRUE;
2900     }
2901
2902   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2903    */
2904   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2905     {
2906       column = list->data;
2907       if (event->window == column->window &&
2908           column->resizable &&
2909           column->window)
2910         {
2911           GtkAllocation button_allocation;
2912           gpointer drag_data;
2913
2914           if (event->type == GDK_2BUTTON_PRESS &&
2915               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2916             {
2917               column->use_resized_width = FALSE;
2918               _gtk_tree_view_column_autosize (tree_view, column);
2919               return TRUE;
2920             }
2921
2922           if (gdk_pointer_grab (column->window, FALSE,
2923                                 GDK_POINTER_MOTION_HINT_MASK |
2924                                 GDK_BUTTON1_MOTION_MASK |
2925                                 GDK_BUTTON_RELEASE_MASK,
2926                                 NULL, NULL, event->time))
2927             return FALSE;
2928
2929           gtk_grab_add (widget);
2930           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2931           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2932
2933           /* block attached dnd signal handler */
2934           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2935           if (drag_data)
2936             g_signal_handlers_block_matched (widget,
2937                                              G_SIGNAL_MATCH_DATA,
2938                                              0, 0, NULL, NULL,
2939                                              drag_data);
2940
2941           gtk_widget_get_allocation (column->button, &button_allocation);
2942           tree_view->priv->drag_pos = i;
2943           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
2944
2945           if (!gtk_widget_has_focus (widget))
2946             gtk_widget_grab_focus (widget);
2947
2948           return TRUE;
2949         }
2950     }
2951   return FALSE;
2952 }
2953
2954 /* GtkWidget::button_release_event helper */
2955 static gboolean
2956 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2957                                           GdkEventButton *event)
2958 {
2959   GtkTreeView *tree_view;
2960   GList *l;
2961   gboolean rtl;
2962
2963   tree_view = GTK_TREE_VIEW (widget);
2964
2965   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2966   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2967   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2968
2969   /* Move the button back */
2970   g_object_ref (tree_view->priv->drag_column->button);
2971   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2972   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2973   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2974   g_object_unref (tree_view->priv->drag_column->button);
2975   gtk_widget_queue_resize (widget);
2976   if (tree_view->priv->drag_column->resizable)
2977     {
2978       gdk_window_raise (tree_view->priv->drag_column->window);
2979       gdk_window_show (tree_view->priv->drag_column->window);
2980     }
2981   else
2982     gdk_window_hide (tree_view->priv->drag_column->window);
2983
2984   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2985
2986   if (rtl)
2987     {
2988       if (tree_view->priv->cur_reorder &&
2989           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2990         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2991                                          tree_view->priv->cur_reorder->right_column);
2992     }
2993   else
2994     {
2995       if (tree_view->priv->cur_reorder &&
2996           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2997         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2998                                          tree_view->priv->cur_reorder->left_column);
2999     }
3000   tree_view->priv->drag_column = NULL;
3001   gdk_window_hide (tree_view->priv->drag_window);
3002
3003   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3004     g_slice_free (GtkTreeViewColumnReorder, l->data);
3005   g_list_free (tree_view->priv->column_drag_info);
3006   tree_view->priv->column_drag_info = NULL;
3007   tree_view->priv->cur_reorder = NULL;
3008
3009   if (tree_view->priv->drag_highlight_window)
3010     gdk_window_hide (tree_view->priv->drag_highlight_window);
3011
3012   /* Reset our flags */
3013   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3014   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3015
3016   return TRUE;
3017 }
3018
3019 /* GtkWidget::button_release_event helper */
3020 static gboolean
3021 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3022                                             GdkEventButton *event)
3023 {
3024   GtkTreeView *tree_view;
3025   gpointer drag_data;
3026
3027   tree_view = GTK_TREE_VIEW (widget);
3028
3029   tree_view->priv->drag_pos = -1;
3030
3031   /* unblock attached dnd signal handler */
3032   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3033   if (drag_data)
3034     g_signal_handlers_unblock_matched (widget,
3035                                        G_SIGNAL_MATCH_DATA,
3036                                        0, 0, NULL, NULL,
3037                                        drag_data);
3038
3039   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3040   gtk_grab_remove (widget);
3041   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
3042                               event->time);
3043   return TRUE;
3044 }
3045
3046 static gboolean
3047 gtk_tree_view_button_release (GtkWidget      *widget,
3048                               GdkEventButton *event)
3049 {
3050   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3051
3052   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3053     return gtk_tree_view_button_release_drag_column (widget, event);
3054
3055   if (tree_view->priv->rubber_band_status)
3056     gtk_tree_view_stop_rubber_band (tree_view);
3057
3058   if (tree_view->priv->pressed_button == event->button)
3059     tree_view->priv->pressed_button = -1;
3060
3061   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3062     return gtk_tree_view_button_release_column_resize (widget, event);
3063
3064   if (tree_view->priv->button_pressed_node == NULL)
3065     return FALSE;
3066
3067   if (event->button == 1)
3068     {
3069       gtk_grab_remove (widget);
3070       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3071           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3072         {
3073           GtkTreePath *path = NULL;
3074
3075           path = _gtk_tree_view_find_path (tree_view,
3076                                            tree_view->priv->button_pressed_tree,
3077                                            tree_view->priv->button_pressed_node);
3078           /* Actually activate the node */
3079           if (tree_view->priv->button_pressed_node->children == NULL)
3080             gtk_tree_view_real_expand_row (tree_view, path,
3081                                            tree_view->priv->button_pressed_tree,
3082                                            tree_view->priv->button_pressed_node,
3083                                            FALSE, TRUE);
3084           else
3085             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3086                                              tree_view->priv->button_pressed_tree,
3087                                              tree_view->priv->button_pressed_node, TRUE);
3088           gtk_tree_path_free (path);
3089         }
3090
3091       tree_view->priv->button_pressed_tree = NULL;
3092       tree_view->priv->button_pressed_node = NULL;
3093     }
3094
3095   return TRUE;
3096 }
3097
3098 static gboolean
3099 gtk_tree_view_grab_broken (GtkWidget          *widget,
3100                            GdkEventGrabBroken *event)
3101 {
3102   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3103
3104   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3105     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3106
3107   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3108     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3109
3110   return TRUE;
3111 }
3112
3113 #if 0
3114 static gboolean
3115 gtk_tree_view_configure (GtkWidget *widget,
3116                          GdkEventConfigure *event)
3117 {
3118   GtkTreeView *tree_view;
3119
3120   tree_view = GTK_TREE_VIEW (widget);
3121   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3122
3123   return FALSE;
3124 }
3125 #endif
3126
3127 /* GtkWidget::motion_event function set.
3128  */
3129
3130 static gboolean
3131 coords_are_over_arrow (GtkTreeView *tree_view,
3132                        GtkRBTree   *tree,
3133                        GtkRBNode   *node,
3134                        /* these are in bin window coords */
3135                        gint         x,
3136                        gint         y)
3137 {
3138   GdkRectangle arrow;
3139   gint x2;
3140
3141   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3142     return FALSE;
3143
3144   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3145     return FALSE;
3146
3147   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3148
3149   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3150
3151   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3152
3153   arrow.width = x2 - arrow.x;
3154
3155   return (x >= arrow.x &&
3156           x < (arrow.x + arrow.width) &&
3157           y >= arrow.y &&
3158           y < (arrow.y + arrow.height));
3159 }
3160
3161 static gboolean
3162 auto_expand_timeout (gpointer data)
3163 {
3164   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3165   GtkTreePath *path;
3166
3167   if (tree_view->priv->prelight_node)
3168     {
3169       path = _gtk_tree_view_find_path (tree_view,
3170                                        tree_view->priv->prelight_tree,
3171                                        tree_view->priv->prelight_node);   
3172
3173       if (tree_view->priv->prelight_node->children)
3174         gtk_tree_view_collapse_row (tree_view, path);
3175       else
3176         gtk_tree_view_expand_row (tree_view, path, FALSE);
3177
3178       gtk_tree_path_free (path);
3179     }
3180
3181   tree_view->priv->auto_expand_timeout = 0;
3182
3183   return FALSE;
3184 }
3185
3186 static void
3187 remove_auto_expand_timeout (GtkTreeView *tree_view)
3188 {
3189   if (tree_view->priv->auto_expand_timeout != 0)
3190     {
3191       g_source_remove (tree_view->priv->auto_expand_timeout);
3192       tree_view->priv->auto_expand_timeout = 0;
3193     }
3194 }
3195
3196 static void
3197 do_prelight (GtkTreeView *tree_view,
3198              GtkRBTree   *tree,
3199              GtkRBNode   *node,
3200              /* these are in bin_window coords */
3201              gint         x,
3202              gint         y)
3203 {
3204   if (tree_view->priv->prelight_tree == tree &&
3205       tree_view->priv->prelight_node == node)
3206     {
3207       /*  We are still on the same node,
3208           but we might need to take care of the arrow  */
3209
3210       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3211         {
3212           gboolean over_arrow;
3213           gboolean flag_set;
3214
3215           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3216           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3217                                              GTK_TREE_VIEW_ARROW_PRELIT);
3218
3219           if (over_arrow != flag_set)
3220             {
3221               if (over_arrow)
3222                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3223                                         GTK_TREE_VIEW_ARROW_PRELIT);
3224               else
3225                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3226                                           GTK_TREE_VIEW_ARROW_PRELIT);
3227
3228               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3229             }
3230         }
3231
3232       return;
3233     }
3234
3235   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3236     {
3237       /*  Unprelight the old node and arrow  */
3238
3239       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3240                              GTK_RBNODE_IS_PRELIT);
3241
3242       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3243           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3244         {
3245           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3246           
3247           gtk_tree_view_draw_arrow (tree_view,
3248                                     tree_view->priv->prelight_tree,
3249                                     tree_view->priv->prelight_node,
3250                                     x,
3251                                     y);
3252         }
3253
3254       _gtk_tree_view_queue_draw_node (tree_view,
3255                                       tree_view->priv->prelight_tree,
3256                                       tree_view->priv->prelight_node,
3257                                       NULL);
3258     }
3259
3260
3261   if (tree_view->priv->hover_expand)
3262     remove_auto_expand_timeout (tree_view);
3263
3264   /*  Set the new prelight values  */
3265   tree_view->priv->prelight_node = node;
3266   tree_view->priv->prelight_tree = tree;
3267
3268   if (!node || !tree)
3269     return;
3270
3271   /*  Prelight the new node and arrow  */
3272
3273   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3274       && coords_are_over_arrow (tree_view, tree, node, x, y))
3275     {
3276       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3277
3278       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3279     }
3280
3281   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3282
3283   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3284
3285   if (tree_view->priv->hover_expand)
3286     {
3287       tree_view->priv->auto_expand_timeout = 
3288         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3289     }
3290 }
3291
3292 static void
3293 prelight_or_select (GtkTreeView *tree_view,
3294                     GtkRBTree   *tree,
3295                     GtkRBNode   *node,
3296                     /* these are in bin_window coords */
3297                     gint         x,
3298                     gint         y)
3299 {
3300   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3301   
3302   if (tree_view->priv->hover_selection &&
3303       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3304       !(tree_view->priv->edited_column &&
3305         tree_view->priv->edited_column->editable_widget))
3306     {
3307       if (node)
3308         {
3309           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3310             {
3311               GtkTreePath *path;
3312               
3313               path = _gtk_tree_view_find_path (tree_view, tree, node);
3314               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3315               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3316                 {
3317                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3318                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3319                 }
3320               gtk_tree_path_free (path);
3321             }
3322         }
3323
3324       else if (mode == GTK_SELECTION_SINGLE)
3325         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3326     }
3327
3328     do_prelight (tree_view, tree, node, x, y);
3329 }
3330
3331 static void
3332 ensure_unprelighted (GtkTreeView *tree_view)
3333 {
3334   do_prelight (tree_view,
3335                NULL, NULL,
3336                -1000, -1000); /* coords not possibly over an arrow */
3337
3338   g_assert (tree_view->priv->prelight_node == NULL);
3339 }
3340
3341 static void
3342 update_prelight (GtkTreeView *tree_view,
3343                  gint         x,
3344                  gint         y)
3345 {
3346   int new_y;
3347   GtkRBTree *tree;
3348   GtkRBNode *node;
3349
3350   if (tree_view->priv->tree == NULL)
3351     return;
3352
3353   if (x == -10000)
3354     {
3355       ensure_unprelighted (tree_view);
3356       return;
3357     }
3358
3359   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3360   if (new_y < 0)
3361     new_y = 0;
3362
3363   _gtk_rbtree_find_offset (tree_view->priv->tree,
3364                            new_y, &tree, &node);
3365
3366   if (node)
3367     prelight_or_select (tree_view, tree, node, x, y);
3368 }
3369
3370
3371
3372
3373 /* Our motion arrow is either a box (in the case of the original spot)
3374  * or an arrow.  It is expander_size wide.
3375  */
3376 /*
3377  * 11111111111111
3378  * 01111111111110
3379  * 00111111111100
3380  * 00011111111000
3381  * 00001111110000
3382  * 00000111100000
3383  * 00000111100000
3384  * 00000111100000
3385  * ~ ~ ~ ~ ~ ~ ~
3386  * 00000111100000
3387  * 00000111100000
3388  * 00000111100000
3389  * 00001111110000
3390  * 00011111111000
3391  * 00111111111100
3392  * 01111111111110
3393  * 11111111111111
3394  */
3395
3396 static void
3397 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3398 {
3399   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3400   GtkWidget *widget = GTK_WIDGET (tree_view);
3401   GdkBitmap *mask = NULL;
3402   gint x;
3403   gint y;
3404   gint width;
3405   gint height;
3406   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3407   GdkWindowAttr attributes;
3408   guint attributes_mask;
3409   cairo_t *cr;
3410
3411   if (!reorder ||
3412       reorder->left_column == tree_view->priv->drag_column ||
3413       reorder->right_column == tree_view->priv->drag_column)
3414     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3415   else if (reorder->left_column || reorder->right_column)
3416     {
3417       GtkAllocation left_allocation, right_allocation;
3418       GdkRectangle visible_rect;
3419
3420       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3421       if (reorder->left_column)
3422         {
3423           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3424           x = left_allocation.x + left_allocation.width;
3425         }
3426       else
3427         {
3428           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3429           x = right_allocation.x;
3430         }
3431
3432       if (x < visible_rect.x)
3433         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3434       else if (x > visible_rect.x + visible_rect.width)
3435         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3436       else
3437         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3438     }
3439
3440   /* We want to draw the rectangle over the initial location. */
3441   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3442     {
3443       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3444         {
3445           GtkAllocation drag_allocation;
3446
3447           if (tree_view->priv->drag_highlight_window)
3448             {
3449               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3450                                         NULL);
3451               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3452             }
3453
3454           attributes.window_type = GDK_WINDOW_CHILD;
3455           attributes.wclass = GDK_INPUT_OUTPUT;
3456           attributes.x = tree_view->priv->drag_column_x;
3457           attributes.y = 0;
3458           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3459           width = attributes.width = drag_allocation.width;
3460           height = attributes.height = drag_allocation.height;
3461           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3462           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3463           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3464           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3465           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3466           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3467
3468           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3469           cr = gdk_cairo_create (mask);
3470
3471           cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3472           cairo_paint (cr);
3473           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3474           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3475           cairo_stroke (cr);
3476           cairo_destroy (cr);
3477
3478           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3479                                          mask, 0, 0);
3480           if (mask) g_object_unref (mask);
3481           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3482         }
3483     }
3484   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3485     {
3486       GtkAllocation button_allocation;
3487
3488       width = tree_view->priv->expander_size;
3489
3490       /* Get x, y, width, height of arrow */
3491       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3492       if (reorder->left_column)
3493         {
3494           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3495           x += button_allocation.x + button_allocation.width - width/2;
3496           height = button_allocation.height;
3497         }
3498       else
3499         {
3500           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3501           x += button_allocation.x - width/2;
3502           height = button_allocation.height;
3503         }
3504       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3505       height += tree_view->priv->expander_size;
3506
3507       /* Create the new window */
3508       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3509         {
3510           if (tree_view->priv->drag_highlight_window)
3511             {
3512               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3513                                         NULL);
3514               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3515             }
3516
3517           attributes.window_type = GDK_WINDOW_TEMP;
3518           attributes.wclass = GDK_INPUT_OUTPUT;
3519           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3520           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3521           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3522           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3523           attributes.x = x;
3524           attributes.y = y;
3525           attributes.width = width;
3526           attributes.height = height;
3527           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3528                                                                    &attributes, attributes_mask);
3529           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3530
3531           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3532           cr = gdk_cairo_create (mask);
3533
3534           cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3535           cairo_paint (cr);
3536           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
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
3545           cairo_destroy (cr);
3546           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3547                                          mask, 0, 0);
3548           if (mask) g_object_unref (mask);
3549         }
3550
3551       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3552       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3553     }
3554   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3555            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3556     {
3557       GtkAllocation allocation;
3558
3559       width = tree_view->priv->expander_size;
3560
3561       /* Get x, y, width, height of arrow */
3562       width = width/2; /* remember, the arrow only takes half the available width */
3563       gdk_window_get_origin (gtk_widget_get_window (widget),
3564                              &x, &y);
3565       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3566         {
3567           gtk_widget_get_allocation (widget, &allocation);
3568           x += allocation.width - width;
3569         }
3570
3571       if (reorder->left_column)
3572         {
3573           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3574           height = allocation.height;
3575         }
3576       else
3577         {
3578           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3579           height = allocation.height;
3580         }
3581
3582       y -= tree_view->priv->expander_size;
3583       height += 2*tree_view->priv->expander_size;
3584
3585       /* Create the new window */
3586       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3587           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3588         {
3589           if (tree_view->priv->drag_highlight_window)
3590             {
3591               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3592                                         NULL);
3593               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3594             }
3595
3596           attributes.window_type = GDK_WINDOW_TEMP;
3597           attributes.wclass = GDK_INPUT_OUTPUT;
3598           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3599           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3600           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3601           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3602           attributes.x = x;
3603           attributes.y = y;
3604           attributes.width = width;
3605           attributes.height = height;
3606           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3607           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3608
3609           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3610           cr = gdk_cairo_create (mask);
3611
3612           cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3613           cairo_paint (cr);
3614           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3615           /* mirror if we're on the left */
3616           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3617             {
3618               cairo_translate (cr, width, 0);
3619               cairo_scale (cr, -1, 1);
3620             }
3621           cairo_move_to (cr, 0, 0);
3622           cairo_line_to (cr, width, width);
3623           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3624           cairo_move_to (cr, 0, height);
3625           cairo_line_to (cr, width, height - width);
3626           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3627           cairo_fill (cr);
3628
3629           cairo_destroy (cr);
3630           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3631                                          mask, 0, 0);
3632           if (mask) g_object_unref (mask);
3633         }
3634
3635       tree_view->priv->drag_column_window_state = arrow_type;
3636       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3637    }
3638   else
3639     {
3640       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3641       gdk_window_hide (tree_view->priv->drag_highlight_window);
3642       return;
3643     }
3644
3645   gdk_window_show (tree_view->priv->drag_highlight_window);
3646   gdk_window_raise (tree_view->priv->drag_highlight_window);
3647 }
3648
3649 static gboolean
3650 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3651                                     GdkEventMotion *event)
3652 {
3653   gint x;
3654   gint new_width;
3655   GtkTreeViewColumn *column;
3656   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3657
3658   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3659
3660   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3661     gtk_widget_get_pointer (widget, &x, NULL);
3662   else
3663     x = event->x;
3664
3665   if (tree_view->priv->hadjustment)
3666     x += tree_view->priv->hadjustment->value;
3667
3668   new_width = gtk_tree_view_new_column_width (tree_view,
3669                                               tree_view->priv->drag_pos, &x);
3670   if (x != tree_view->priv->x_drag &&
3671       (new_width != column->fixed_width))
3672     {
3673       column->use_resized_width = TRUE;
3674       column->resized_width = new_width;
3675       if (column->expand)
3676         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3677       gtk_widget_queue_resize (widget);
3678     }
3679
3680   return FALSE;
3681 }
3682
3683
3684 static void
3685 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3686 {
3687   GtkTreeViewColumnReorder *reorder = NULL;
3688   GList *list;
3689   gint mouse_x;
3690
3691   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3692   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3693     {
3694       reorder = (GtkTreeViewColumnReorder *) list->data;
3695       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3696         break;
3697       reorder = NULL;
3698     }
3699
3700   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3701       return;*/
3702
3703   tree_view->priv->cur_reorder = reorder;
3704   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3705 }
3706
3707 static void
3708 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3709 {
3710   GdkRectangle visible_rect;
3711   gint y;
3712   gint offset;
3713
3714   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3715   y += tree_view->priv->dy;
3716
3717   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3718
3719   /* see if we are near the edge. */
3720   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3721   if (offset > 0)
3722     {
3723       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3724       if (offset < 0)
3725         return;
3726     }
3727
3728   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3729                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3730 }
3731
3732 static gboolean
3733 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3734 {
3735   GdkRectangle visible_rect;
3736   gint x;
3737   gint offset;
3738
3739   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3740
3741   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3742
3743   /* See if we are near the edge. */
3744   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3745   if (offset > 0)
3746     {
3747       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3748       if (offset < 0)
3749         return TRUE;
3750     }
3751   offset = offset/3;
3752
3753   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3754                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3755
3756   return TRUE;
3757
3758 }
3759
3760 static gboolean
3761 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3762                                   GdkEventMotion *event)
3763 {
3764   GtkAllocation allocation, button_allocation;
3765   GtkTreeView *tree_view = (GtkTreeView *) widget;
3766   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3767   gint x, y;
3768
3769   /* Sanity Check */
3770   if ((column == NULL) ||
3771       (event->window != tree_view->priv->drag_window))
3772     return FALSE;
3773
3774   /* Handle moving the header */
3775   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3776   gtk_widget_get_allocation (widget, &allocation);
3777   gtk_widget_get_allocation (column->button, &button_allocation);
3778   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3779              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3780   gdk_window_move (tree_view->priv->drag_window, x, y);
3781   
3782   /* autoscroll, if needed */
3783   gtk_tree_view_horizontal_autoscroll (tree_view);
3784   /* Update the current reorder position and arrow; */
3785   gtk_tree_view_update_current_reorder (tree_view);
3786
3787   return TRUE;
3788 }
3789
3790 static void
3791 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3792 {
3793   remove_scroll_timeout (tree_view);
3794   gtk_grab_remove (GTK_WIDGET (tree_view));
3795
3796   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3797     {
3798       GtkTreePath *tmp_path;
3799
3800       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3801
3802       /* The anchor path should be set to the start path */
3803       tmp_path = _gtk_tree_view_find_path (tree_view,
3804                                            tree_view->priv->rubber_band_start_tree,
3805                                            tree_view->priv->rubber_band_start_node);
3806
3807       if (tree_view->priv->anchor)
3808         gtk_tree_row_reference_free (tree_view->priv->anchor);
3809
3810       tree_view->priv->anchor =
3811         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3812                                           tree_view->priv->model,
3813                                           tmp_path);
3814
3815       gtk_tree_path_free (tmp_path);
3816
3817       /* ... and the cursor to the end path */
3818       tmp_path = _gtk_tree_view_find_path (tree_view,
3819                                            tree_view->priv->rubber_band_end_tree,
3820                                            tree_view->priv->rubber_band_end_node);
3821       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3822       gtk_tree_path_free (tmp_path);
3823
3824       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3825     }
3826
3827   /* Clear status variables */
3828   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3829   tree_view->priv->rubber_band_shift = 0;
3830   tree_view->priv->rubber_band_ctrl = 0;
3831
3832   tree_view->priv->rubber_band_start_node = NULL;
3833   tree_view->priv->rubber_band_start_tree = NULL;
3834   tree_view->priv->rubber_band_end_node = NULL;
3835   tree_view->priv->rubber_band_end_tree = NULL;
3836 }
3837
3838 static void
3839 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3840                                                  GtkRBTree   *start_tree,
3841                                                  GtkRBNode   *start_node,
3842                                                  GtkRBTree   *end_tree,
3843                                                  GtkRBNode   *end_node,
3844                                                  gboolean     select,
3845                                                  gboolean     skip_start,
3846                                                  gboolean     skip_end)
3847 {
3848   if (start_node == end_node)
3849     return;
3850
3851   /* We skip the first node and jump inside the loop */
3852   if (skip_start)
3853     goto skip_first;
3854
3855   do
3856     {
3857       /* Small optimization by assuming insensitive nodes are never
3858        * selected.
3859        */
3860       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3861         {
3862           GtkTreePath *path;
3863           gboolean selectable;
3864
3865           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3866           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3867           gtk_tree_path_free (path);
3868
3869           if (!selectable)
3870             goto node_not_selectable;
3871         }
3872
3873       if (select)
3874         {
3875           if (tree_view->priv->rubber_band_shift)
3876             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3877           else if (tree_view->priv->rubber_band_ctrl)
3878             {
3879               /* Toggle the selection state */
3880               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3881                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3882               else
3883                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3884             }
3885           else
3886             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3887         }
3888       else
3889         {
3890           /* Mirror the above */
3891           if (tree_view->priv->rubber_band_shift)
3892             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3893           else if (tree_view->priv->rubber_band_ctrl)
3894             {
3895               /* Toggle the selection state */
3896               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3897                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3898               else
3899                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3900             }
3901           else
3902             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3903         }
3904
3905       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3906
3907 node_not_selectable:
3908       if (start_node == end_node)
3909         break;
3910
3911 skip_first:
3912
3913       if (start_node->children)
3914         {
3915           start_tree = start_node->children;
3916           start_node = start_tree->root;
3917           while (start_node->left != start_tree->nil)
3918             start_node = start_node->left;
3919         }
3920       else
3921         {
3922           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3923
3924           if (!start_tree)
3925             /* Ran out of tree */
3926             break;
3927         }
3928
3929       if (skip_end && start_node == end_node)
3930         break;
3931     }
3932   while (TRUE);
3933 }
3934
3935 static void
3936 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3937 {
3938   GtkRBTree *start_tree, *end_tree;
3939   GtkRBNode *start_node, *end_node;
3940
3941   _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);
3942   _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);
3943
3944   /* Handle the start area first */
3945   if (!tree_view->priv->rubber_band_start_node)
3946     {
3947       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3948                                                        start_tree,
3949                                                        start_node,
3950                                                        end_tree,
3951                                                        end_node,
3952                                                        TRUE,
3953                                                        FALSE,
3954                                                        FALSE);
3955     }
3956   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3957            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3958     {
3959       /* New node is above the old one; selection became bigger */
3960       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3961                                                        start_tree,
3962                                                        start_node,
3963                                                        tree_view->priv->rubber_band_start_tree,
3964                                                        tree_view->priv->rubber_band_start_node,
3965                                                        TRUE,
3966                                                        FALSE,
3967                                                        TRUE);
3968     }
3969   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3970            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3971     {
3972       /* New node is below the old one; selection became smaller */
3973       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3974                                                        tree_view->priv->rubber_band_start_tree,
3975                                                        tree_view->priv->rubber_band_start_node,
3976                                                        start_tree,
3977                                                        start_node,
3978                                                        FALSE,
3979                                                        FALSE,
3980                                                        TRUE);
3981     }
3982
3983   tree_view->priv->rubber_band_start_tree = start_tree;
3984   tree_view->priv->rubber_band_start_node = start_node;
3985
3986   /* Next, handle the end area */
3987   if (!tree_view->priv->rubber_band_end_node)
3988     {
3989       /* In the event this happens, start_node was also NULL; this case is
3990        * handled above.
3991        */
3992     }
3993   else if (!end_node)
3994     {
3995       /* Find the last node in the tree */
3996       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3997                                &end_tree, &end_node);
3998
3999       /* Selection reached end of the tree */
4000       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4001                                                        tree_view->priv->rubber_band_end_tree,
4002                                                        tree_view->priv->rubber_band_end_node,
4003                                                        end_tree,
4004                                                        end_node,
4005                                                        TRUE,
4006                                                        TRUE,
4007                                                        FALSE);
4008     }
4009   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4010            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4011     {
4012       /* New node is below the old one; selection became bigger */
4013       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4014                                                        tree_view->priv->rubber_band_end_tree,
4015                                                        tree_view->priv->rubber_band_end_node,
4016                                                        end_tree,
4017                                                        end_node,
4018                                                        TRUE,
4019                                                        TRUE,
4020                                                        FALSE);
4021     }
4022   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4023            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4024     {
4025       /* New node is above the old one; selection became smaller */
4026       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4027                                                        end_tree,
4028                                                        end_node,
4029                                                        tree_view->priv->rubber_band_end_tree,
4030                                                        tree_view->priv->rubber_band_end_node,
4031                                                        FALSE,
4032                                                        TRUE,
4033                                                        FALSE);
4034     }
4035
4036   tree_view->priv->rubber_band_end_tree = end_tree;
4037   tree_view->priv->rubber_band_end_node = end_node;
4038 }
4039
4040 static void
4041 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4042 {
4043   gint x, y;
4044   GdkRectangle old_area;
4045   GdkRectangle new_area;
4046   GdkRectangle common;
4047   cairo_region_t *invalid_region;
4048
4049   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4050   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4051   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4052   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4053
4054   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4055
4056   x = MAX (x, 0);
4057   y = MAX (y, 0) + tree_view->priv->dy;
4058
4059   new_area.x = MIN (tree_view->priv->press_start_x, x);
4060   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4061   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4062   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4063
4064   invalid_region = cairo_region_create_rectangle (&old_area);
4065   cairo_region_union_rectangle (invalid_region, &new_area);
4066
4067   gdk_rectangle_intersect (&old_area, &new_area, &common);
4068   if (common.width > 2 && common.height > 2)
4069     {
4070       cairo_region_t *common_region;
4071
4072       /* make sure the border is invalidated */
4073       common.x += 1;
4074       common.y += 1;
4075       common.width -= 2;
4076       common.height -= 2;
4077
4078       common_region = cairo_region_create_rectangle (&common);
4079
4080       cairo_region_subtract (invalid_region, common_region);
4081       cairo_region_destroy (common_region);
4082     }
4083
4084   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4085
4086   cairo_region_destroy (invalid_region);
4087
4088   tree_view->priv->rubber_band_x = x;
4089   tree_view->priv->rubber_band_y = y;
4090
4091   gtk_tree_view_update_rubber_band_selection (tree_view);
4092 }
4093
4094 static void
4095 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4096                                 GdkRectangle *area)
4097 {
4098   GtkStyle *style;
4099   cairo_t *cr;
4100   GdkRectangle rect;
4101   GdkRectangle rubber_rect;
4102
4103   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4104   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4105   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4106   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4107
4108   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4109     return;
4110
4111   cr = gdk_cairo_create (tree_view->priv->bin_window);
4112   cairo_set_line_width (cr, 1.0);
4113
4114   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4115
4116   cairo_set_source_rgba (cr,
4117                          style->fg[GTK_STATE_NORMAL].red / 65535.,
4118                          style->fg[GTK_STATE_NORMAL].green / 65535.,
4119                          style->fg[GTK_STATE_NORMAL].blue / 65535.,
4120                          .25);
4121
4122   gdk_cairo_rectangle (cr, &rect);
4123   cairo_clip (cr);
4124   cairo_paint (cr);
4125
4126   cairo_set_source_rgb (cr,
4127                         style->fg[GTK_STATE_NORMAL].red / 65535.,
4128                         style->fg[GTK_STATE_NORMAL].green / 65535.,
4129                         style->fg[GTK_STATE_NORMAL].blue / 65535.);
4130
4131   cairo_rectangle (cr,
4132                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4133                    rubber_rect.width - 1, rubber_rect.height - 1);
4134   cairo_stroke (cr);
4135
4136   cairo_destroy (cr);
4137 }
4138
4139 static gboolean
4140 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4141                                  GdkEventMotion *event)
4142 {
4143   GtkTreeView *tree_view;
4144   GtkRBTree *tree;
4145   GtkRBNode *node;
4146   gint new_y;
4147
4148   tree_view = (GtkTreeView *) widget;
4149
4150   if (tree_view->priv->tree == NULL)
4151     return FALSE;
4152
4153   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4154     {
4155       gtk_grab_add (GTK_WIDGET (tree_view));
4156       gtk_tree_view_update_rubber_band (tree_view);
4157
4158       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4159     }
4160   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4161     {
4162       gtk_tree_view_update_rubber_band (tree_view);
4163
4164       add_scroll_timeout (tree_view);
4165     }
4166
4167   /* only check for an initiated drag when a button is pressed */
4168   if (tree_view->priv->pressed_button >= 0
4169       && !tree_view->priv->rubber_band_status)
4170     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4171
4172   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4173   if (new_y < 0)
4174     new_y = 0;
4175
4176   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4177
4178   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4179   if ((tree_view->priv->button_pressed_node != NULL) &&
4180       (tree_view->priv->button_pressed_node != node))
4181     node = NULL;
4182
4183   tree_view->priv->event_last_x = event->x;
4184   tree_view->priv->event_last_y = event->y;
4185
4186   prelight_or_select (tree_view, tree, node, event->x, event->y);
4187
4188   return TRUE;
4189 }
4190
4191 static gboolean
4192 gtk_tree_view_motion (GtkWidget      *widget,
4193                       GdkEventMotion *event)
4194 {
4195   GtkTreeView *tree_view;
4196
4197   tree_view = (GtkTreeView *) widget;
4198
4199   /* Resizing a column */
4200   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4201     return gtk_tree_view_motion_resize_column (widget, event);
4202
4203   /* Drag column */
4204   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4205     return gtk_tree_view_motion_drag_column (widget, event);
4206
4207   /* Sanity check it */
4208   if (event->window == tree_view->priv->bin_window)
4209     return gtk_tree_view_motion_bin_window (widget, event);
4210
4211   return FALSE;
4212 }
4213
4214 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4215  * the tree is empty.
4216  */
4217 static void
4218 invalidate_empty_focus (GtkTreeView *tree_view)
4219 {
4220   GdkRectangle area;
4221
4222   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4223     return;
4224
4225   area.x = 0;
4226   area.y = 0;
4227   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4228   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4229 }
4230
4231 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4232  * is empty.
4233  */
4234 static void
4235 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4236 {
4237   GtkWidget *widget = GTK_WIDGET (tree_view);
4238   gint w, h;
4239
4240   if (!gtk_widget_has_focus (widget))
4241     return;
4242
4243   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4244
4245   w -= 2;
4246   h -= 2;
4247
4248   if (w > 0 && h > 0)
4249     gtk_paint_focus (gtk_widget_get_style (widget),
4250                      tree_view->priv->bin_window,
4251                      gtk_widget_get_state (widget),
4252                      clip_area,
4253                      widget,
4254                      NULL,
4255                      1, 1, w, h);
4256 }
4257
4258 typedef enum {
4259   GTK_TREE_VIEW_GRID_LINE,
4260   GTK_TREE_VIEW_TREE_LINE,
4261   GTK_TREE_VIEW_FOREGROUND_LINE
4262 } GtkTreeViewLineType;
4263
4264 static void
4265 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4266                          GdkWindow           *window,
4267                          GtkTreeViewLineType  type,
4268                          int                  x1,
4269                          int                  y1,
4270                          int                  x2,
4271                          int                  y2)
4272 {
4273   cairo_t *cr;
4274
4275   cr = gdk_cairo_create (window);
4276
4277   switch (type)
4278     {
4279     case GTK_TREE_VIEW_TREE_LINE:
4280       cairo_set_source_rgb (cr, 0, 0, 0);
4281       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4282       if (tree_view->priv->tree_line_dashes[0])
4283         cairo_set_dash (cr, 
4284                         tree_view->priv->tree_line_dashes,
4285                         2, 0.5);
4286       break;
4287     case GTK_TREE_VIEW_GRID_LINE:
4288       cairo_set_source_rgb (cr, 0, 0, 0);
4289       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4290       if (tree_view->priv->grid_line_dashes[0])
4291         cairo_set_dash (cr, 
4292                         tree_view->priv->grid_line_dashes,
4293                         2, 0.5);
4294       break;
4295     default:
4296       g_assert_not_reached ();
4297       /* fall through */
4298     case GTK_TREE_VIEW_FOREGROUND_LINE:
4299       cairo_set_line_width (cr, 1.0);
4300       gdk_cairo_set_source_color (cr,
4301                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4302       break;
4303     }
4304
4305   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4306   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4307   cairo_stroke (cr);
4308
4309   cairo_destroy (cr);
4310 }
4311                          
4312 static void
4313 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4314                                GdkEventExpose *event,
4315                                gint            n_visible_columns)
4316 {
4317   GList *list = tree_view->priv->columns;
4318   gint i = 0;
4319   gint current_x = 0;
4320
4321   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4322       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4323     return;
4324
4325   /* Only draw the lines for visible rows and columns */
4326   for (list = tree_view->priv->columns; list; list = list->next, i++)
4327     {
4328       GtkTreeViewColumn *column = list->data;
4329
4330       /* We don't want a line for the last column */
4331       if (i == n_visible_columns - 1)
4332         break;
4333
4334       if (! column->visible)
4335         continue;
4336
4337       current_x += column->width;
4338
4339       gtk_tree_view_draw_line (tree_view, event->window,
4340                                GTK_TREE_VIEW_GRID_LINE,
4341                                current_x - 1, 0,
4342                                current_x - 1, tree_view->priv->height);
4343     }
4344 }
4345
4346 /* Warning: Very scary function.
4347  * Modify at your own risk
4348  *
4349  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4350  * FIXME: It's not...
4351  */
4352 static gboolean
4353 gtk_tree_view_bin_expose (GtkWidget      *widget,
4354                           GdkEventExpose *event)
4355 {
4356   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4357   GtkTreePath *path;
4358   GtkStyle *style;
4359   GtkRBTree *tree;
4360   GList *list;
4361   GtkRBNode *node;
4362   GtkRBNode *cursor = NULL;
4363   GtkRBTree *cursor_tree = NULL;
4364   GtkRBNode *drag_highlight = NULL;
4365   GtkRBTree *drag_highlight_tree = NULL;
4366   GtkTreeIter iter;
4367   gint new_y;
4368   gint y_offset, cell_offset;
4369   gint max_height;
4370   gint depth;
4371   GdkRectangle background_area;
4372   GdkRectangle cell_area;
4373   guint flags;
4374   gint highlight_x;
4375   gint expander_cell_width;
4376   gint bin_window_width;
4377   gint bin_window_height;
4378   GtkTreePath *cursor_path;
4379   GtkTreePath *drag_dest_path;
4380   GList *first_column, *last_column;
4381   gint vertical_separator;
4382   gint horizontal_separator;
4383   gint focus_line_width;
4384   gboolean allow_rules;
4385   gboolean has_special_cell;
4386   gboolean rtl;
4387   gint n_visible_columns;
4388   gint pointer_x, pointer_y;
4389   gint grid_line_width;
4390   gboolean got_pointer = FALSE;
4391   gboolean draw_vgrid_lines, draw_hgrid_lines;
4392
4393   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4394
4395   gtk_widget_style_get (widget,
4396                         "horizontal-separator", &horizontal_separator,
4397                         "vertical-separator", &vertical_separator,
4398                         "allow-rules", &allow_rules,
4399                         "focus-line-width", &focus_line_width,
4400                         NULL);
4401
4402   if (tree_view->priv->tree == NULL)
4403     {
4404       draw_empty_focus (tree_view, &event->area);
4405       return TRUE;
4406     }
4407
4408   /* clip event->area to the visible area */
4409   if (event->area.height < 0)
4410     return TRUE;
4411
4412   validate_visible_area (tree_view);
4413
4414   style = gtk_widget_get_style (widget);
4415
4416   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4417
4418   if (new_y < 0)
4419     new_y = 0;
4420   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4421   gdk_drawable_get_size (tree_view->priv->bin_window,
4422                          &bin_window_width, &bin_window_height);
4423
4424   if (tree_view->priv->height < bin_window_height)
4425     {
4426       gtk_paint_flat_box (style,
4427                           event->window,
4428                           gtk_widget_get_state (widget),
4429                           GTK_SHADOW_NONE,
4430                           &event->area,
4431                           widget,
4432                           "cell_even",
4433                           0, tree_view->priv->height,
4434                           bin_window_width,
4435                           bin_window_height - tree_view->priv->height);
4436     }
4437
4438   if (node == NULL)
4439     return TRUE;
4440
4441   /* find the path for the node */
4442   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4443                                    tree,
4444                                    node);
4445   gtk_tree_model_get_iter (tree_view->priv->model,
4446                            &iter,
4447                            path);
4448   depth = gtk_tree_path_get_depth (path);
4449   gtk_tree_path_free (path);
4450   
4451   cursor_path = NULL;
4452   drag_dest_path = NULL;
4453
4454   if (tree_view->priv->cursor)
4455     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4456
4457   if (cursor_path)
4458     _gtk_tree_view_find_node (tree_view, cursor_path,
4459                               &cursor_tree, &cursor);
4460
4461   if (tree_view->priv->drag_dest_row)
4462     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4463
4464   if (drag_dest_path)
4465     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4466                               &drag_highlight_tree, &drag_highlight);
4467
4468   draw_vgrid_lines =
4469     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4470     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4471   draw_hgrid_lines =
4472     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4473     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4474
4475   if (draw_vgrid_lines || draw_hgrid_lines)
4476     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4477   
4478   n_visible_columns = 0;
4479   for (list = tree_view->priv->columns; list; list = list->next)
4480     {
4481       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4482         continue;
4483       n_visible_columns ++;
4484     }
4485
4486   /* Find the last column */
4487   for (last_column = g_list_last (tree_view->priv->columns);
4488        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4489        last_column = last_column->prev)
4490     ;
4491
4492   /* and the first */
4493   for (first_column = g_list_first (tree_view->priv->columns);
4494        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4495        first_column = first_column->next)
4496     ;
4497
4498   /* Actually process the expose event.  To do this, we want to
4499    * start at the first node of the event, and walk the tree in
4500    * order, drawing each successive node.
4501    */
4502
4503   do
4504     {
4505       gboolean parity;
4506       gboolean is_separator = FALSE;
4507       gboolean is_first = FALSE;
4508       gboolean is_last = FALSE;
4509       
4510       is_separator = row_is_separator (tree_view, &iter, NULL);
4511
4512       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4513
4514       cell_offset = 0;
4515       highlight_x = 0; /* should match x coord of first cell */
4516       expander_cell_width = 0;
4517
4518       background_area.y = y_offset + event->area.y;
4519       background_area.height = max_height;
4520
4521       flags = 0;
4522
4523       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4524         flags |= GTK_CELL_RENDERER_PRELIT;
4525
4526       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4527         flags |= GTK_CELL_RENDERER_SELECTED;
4528
4529       parity = _gtk_rbtree_node_find_parity (tree, node);
4530
4531       /* we *need* to set cell data on all cells before the call
4532        * to _has_special_cell, else _has_special_cell() does not
4533        * return a correct value.
4534        */
4535       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4536            list;
4537            list = (rtl ? list->prev : list->next))
4538         {
4539           GtkTreeViewColumn *column = list->data;
4540           gtk_tree_view_column_cell_set_cell_data (column,
4541                                                    tree_view->priv->model,
4542                                                    &iter,
4543                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4544                                                    node->children?TRUE:FALSE);
4545         }
4546
4547       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4548
4549       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4550            list;
4551            list = (rtl ? list->prev : list->next))
4552         {
4553           GtkTreeViewColumn *column = list->data;
4554           const gchar *detail = NULL;
4555           gchar new_detail[128];
4556           GtkStateType state;
4557
4558           if (!column->visible)
4559             continue;
4560
4561           if (cell_offset > event->area.x + event->area.width ||
4562               cell_offset + column->width < event->area.x)
4563             {
4564               cell_offset += column->width;
4565               continue;
4566             }
4567
4568           if (column->show_sort_indicator)
4569             flags |= GTK_CELL_RENDERER_SORTED;
4570           else
4571             flags &= ~GTK_CELL_RENDERER_SORTED;
4572
4573           if (cursor == node)
4574             flags |= GTK_CELL_RENDERER_FOCUSED;
4575           else
4576             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4577
4578           background_area.x = cell_offset;
4579           background_area.width = column->width;
4580
4581           cell_area = background_area;
4582           cell_area.y += vertical_separator / 2;
4583           cell_area.x += horizontal_separator / 2;
4584           cell_area.height -= vertical_separator;
4585           cell_area.width -= horizontal_separator;
4586
4587           if (draw_vgrid_lines)
4588             {
4589               if (list == first_column)
4590                 {
4591                   cell_area.width -= grid_line_width / 2;
4592                 }
4593               else if (list == last_column)
4594                 {
4595                   cell_area.x += grid_line_width / 2;
4596                   cell_area.width -= grid_line_width / 2;
4597                 }
4598               else
4599                 {
4600                   cell_area.x += grid_line_width / 2;
4601                   cell_area.width -= grid_line_width;
4602                 }
4603             }
4604
4605           if (draw_hgrid_lines)
4606             {
4607               cell_area.y += grid_line_width / 2;
4608               cell_area.height -= grid_line_width;
4609             }
4610
4611           if (cairo_region_contains_rectangle (event->region, &background_area) == CAIRO_REGION_OVERLAP_OUT)
4612             {
4613               cell_offset += column->width;
4614               continue;
4615             }
4616
4617           gtk_tree_view_column_cell_set_cell_data (column,
4618                                                    tree_view->priv->model,
4619                                                    &iter,
4620                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4621                                                    node->children?TRUE:FALSE);
4622
4623           /* Select the detail for drawing the cell.  relevant
4624            * factors are parity, sortedness, and whether to
4625            * display rules.
4626            */
4627           if (allow_rules && tree_view->priv->has_rules)
4628             {
4629               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4630                   n_visible_columns >= 3)
4631                 {
4632                   if (parity)
4633                     detail = "cell_odd_ruled_sorted";
4634                   else
4635                     detail = "cell_even_ruled_sorted";
4636                 }
4637               else
4638                 {
4639                   if (parity)
4640                     detail = "cell_odd_ruled";
4641                   else
4642                     detail = "cell_even_ruled";
4643                 }
4644             }
4645           else
4646             {
4647               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4648                   n_visible_columns >= 3)
4649                 {
4650                   if (parity)
4651                     detail = "cell_odd_sorted";
4652                   else
4653                     detail = "cell_even_sorted";
4654                 }
4655               else
4656                 {
4657                   if (parity)
4658                     detail = "cell_odd";
4659                   else
4660                     detail = "cell_even";
4661                 }
4662             }
4663
4664           g_assert (detail);
4665
4666           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4667             state = GTK_STATE_INSENSITIVE;          
4668           else if (flags & GTK_CELL_RENDERER_SELECTED)
4669             state = GTK_STATE_SELECTED;
4670           else
4671             state = GTK_STATE_NORMAL;
4672
4673           /* Draw background */
4674           is_first = (rtl ? !list->next : !list->prev);
4675           is_last = (rtl ? !list->prev : !list->next);
4676
4677           /* (I don't like the snprintfs either, but couldn't find a
4678            * less messy way).
4679            */
4680           if (is_first && is_last)
4681             g_snprintf (new_detail, 127, "%s", detail);
4682           else if (is_first)
4683             g_snprintf (new_detail, 127, "%s_start", detail);
4684           else if (is_last)
4685             g_snprintf (new_detail, 127, "%s_end", detail);
4686           else
4687             g_snprintf (new_detail, 127, "%s_middle", detail);
4688
4689           gtk_paint_flat_box (style,
4690                               event->window,
4691                               state,
4692                               GTK_SHADOW_NONE,
4693                               &event->area,
4694                               widget,
4695                               new_detail,
4696                               background_area.x,
4697                               background_area.y,
4698                               background_area.width,
4699                               background_area.height);
4700
4701           if (gtk_tree_view_is_expander_column (tree_view, column))
4702             {
4703               if (!rtl)
4704                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4705               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4706
4707               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4708                 {
4709                   if (!rtl)
4710                     cell_area.x += depth * tree_view->priv->expander_size;
4711                   cell_area.width -= depth * tree_view->priv->expander_size;
4712                 }
4713
4714               /* If we have an expander column, the highlight underline
4715                * starts with that column, so that it indicates which
4716                * level of the tree we're dropping at.
4717                */
4718               highlight_x = cell_area.x;
4719               expander_cell_width = cell_area.width;
4720
4721               if (is_separator)
4722                 gtk_paint_hline (style,
4723                                  event->window,
4724                                  state,
4725                                  &cell_area,
4726                                  widget,
4727                                  NULL,
4728                                  cell_area.x,
4729                                  cell_area.x + cell_area.width,
4730                                  cell_area.y + cell_area.height / 2);
4731               else
4732                 _gtk_tree_view_column_cell_render (column,
4733                                                    event->window,
4734                                                    &background_area,
4735                                                    &cell_area,
4736                                                    &event->area,
4737                                                    flags);
4738               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4739                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4740                 {
4741                   if (!got_pointer)
4742                     {
4743                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4744                                               &pointer_x, &pointer_y, NULL);
4745                       got_pointer = TRUE;
4746                     }
4747
4748                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4749                                             tree,
4750                                             node,
4751                                             pointer_x, pointer_y);
4752                 }
4753             }
4754           else
4755             {
4756               if (is_separator)
4757                 gtk_paint_hline (style,
4758                                  event->window,
4759                                  state,
4760                                  &cell_area,
4761                                  widget,
4762                                  NULL,
4763                                  cell_area.x,
4764                                  cell_area.x + cell_area.width,
4765                                  cell_area.y + cell_area.height / 2);
4766               else
4767                 _gtk_tree_view_column_cell_render (column,
4768                                                    event->window,
4769                                                    &background_area,
4770                                                    &cell_area,
4771                                                    &event->area,
4772                                                    flags);
4773             }
4774
4775           if (draw_hgrid_lines)
4776             {
4777               if (background_area.y > 0)
4778                 gtk_tree_view_draw_line (tree_view, event->window,
4779                                          GTK_TREE_VIEW_GRID_LINE,
4780                                          background_area.x, background_area.y,
4781                                          background_area.x + background_area.width,
4782                                          background_area.y);
4783
4784               if (y_offset + max_height >= event->area.height)
4785                 gtk_tree_view_draw_line (tree_view, event->window,
4786                                          GTK_TREE_VIEW_GRID_LINE,
4787                                          background_area.x, background_area.y + max_height,
4788                                          background_area.x + background_area.width,
4789                                          background_area.y + max_height);
4790             }
4791
4792           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4793               tree_view->priv->tree_lines_enabled)
4794             {
4795               gint x = background_area.x;
4796               gint mult = rtl ? -1 : 1;
4797               gint y0 = background_area.y;
4798               gint y1 = background_area.y + background_area.height/2;
4799               gint y2 = background_area.y + background_area.height;
4800
4801               if (rtl)
4802                 x += background_area.width - 1;
4803
4804               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4805                   && depth > 1)
4806                 {
4807                   gtk_tree_view_draw_line (tree_view, event->window,
4808                                            GTK_TREE_VIEW_TREE_LINE,
4809                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4810                                            y1,
4811                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4812                                            y1);
4813                 }
4814               else if (depth > 1)
4815                 {
4816                   gtk_tree_view_draw_line (tree_view, event->window,
4817                                            GTK_TREE_VIEW_TREE_LINE,
4818                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4819                                            y1,
4820                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4821                                            y1);
4822                 }
4823
4824               if (depth > 1)
4825                 {
4826                   gint i;
4827                   GtkRBNode *tmp_node;
4828                   GtkRBTree *tmp_tree;
4829
4830                   if (!_gtk_rbtree_next (tree, node))
4831                     gtk_tree_view_draw_line (tree_view, event->window,
4832                                              GTK_TREE_VIEW_TREE_LINE,
4833                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4834                                              y0,
4835                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4836                                              y1);
4837                   else
4838                     gtk_tree_view_draw_line (tree_view, event->window,
4839                                              GTK_TREE_VIEW_TREE_LINE,
4840                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4841                                              y0,
4842                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4843                                              y2);
4844
4845                   tmp_node = tree->parent_node;
4846                   tmp_tree = tree->parent_tree;
4847
4848                   for (i = depth - 2; i > 0; i--)
4849                     {
4850                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4851                         gtk_tree_view_draw_line (tree_view, event->window,
4852                                                  GTK_TREE_VIEW_TREE_LINE,
4853                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4854                                                  y0,
4855                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4856                                                  y2);
4857
4858                       tmp_node = tmp_tree->parent_node;
4859                       tmp_tree = tmp_tree->parent_tree;
4860                     }
4861                 }
4862             }
4863
4864           if (node == cursor && has_special_cell &&
4865               ((column == tree_view->priv->focus_column &&
4866                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4867                 gtk_widget_has_focus (widget)) ||
4868                (column == tree_view->priv->edited_column)))
4869             {
4870               _gtk_tree_view_column_cell_draw_focus (column,
4871                                                      event->window,
4872                                                      &background_area,
4873                                                      &cell_area,
4874                                                      &event->area,
4875                                                      flags);
4876             }
4877
4878           cell_offset += column->width;
4879         }
4880
4881       if (node == drag_highlight)
4882         {
4883           /* Draw indicator for the drop
4884            */
4885           gint highlight_y = -1;
4886           GtkRBTree *tree = NULL;
4887           GtkRBNode *node = NULL;
4888           gint width;
4889
4890           switch (tree_view->priv->drag_dest_pos)
4891             {
4892             case GTK_TREE_VIEW_DROP_BEFORE:
4893               highlight_y = background_area.y - 1;
4894               if (highlight_y < 0)
4895                       highlight_y = 0;
4896               break;
4897
4898             case GTK_TREE_VIEW_DROP_AFTER:
4899               highlight_y = background_area.y + background_area.height - 1;
4900               break;
4901
4902             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4903             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4904               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4905
4906               if (tree == NULL)
4907                 break;
4908               gdk_drawable_get_size (tree_view->priv->bin_window,
4909                                      &width, NULL);
4910
4911               gtk_paint_focus (style,
4912                                tree_view->priv->bin_window,
4913                                gtk_widget_get_state (widget),
4914                                &event->area,
4915                                widget,
4916                                (is_first
4917                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4918                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4919                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4920                                    - focus_line_width / 2,
4921                                 width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4922                                        - focus_line_width + 1);
4923               break;
4924             }
4925
4926           if (highlight_y >= 0)
4927             {
4928               gtk_tree_view_draw_line (tree_view, event->window,
4929                                        GTK_TREE_VIEW_FOREGROUND_LINE,
4930                                        rtl ? highlight_x + expander_cell_width : highlight_x,
4931                                        highlight_y,
4932                                        rtl ? 0 : bin_window_width,
4933                                        highlight_y);
4934             }
4935         }
4936
4937       /* draw the big row-spanning focus rectangle, if needed */
4938       if (!has_special_cell && node == cursor &&
4939           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4940           gtk_widget_has_focus (widget))
4941         {
4942           gint tmp_y, tmp_height;
4943           gint width;
4944           GtkStateType focus_rect_state;
4945
4946           focus_rect_state =
4947             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4948             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4949              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4950               GTK_STATE_NORMAL));
4951
4952           gdk_drawable_get_size (tree_view->priv->bin_window,
4953                                  &width, NULL);
4954           
4955           if (draw_hgrid_lines)
4956             {
4957               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4958               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4959             }
4960           else
4961             {
4962               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4963               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4964             }
4965
4966           gtk_paint_focus (style,
4967                            tree_view->priv->bin_window,
4968                            focus_rect_state,
4969                            &event->area,
4970                            widget,
4971                            (is_first
4972                             ? (is_last ? "treeview" : "treeview-left" )
4973                             : (is_last ? "treeview-right" : "treeview-middle" )),
4974                            0, tmp_y,
4975                            width, tmp_height);
4976         }
4977
4978       y_offset += max_height;
4979       if (node->children)
4980         {
4981           GtkTreeIter parent = iter;
4982           gboolean has_child;
4983
4984           tree = node->children;
4985           node = tree->root;
4986
4987           g_assert (node != tree->nil);
4988
4989           while (node->left != tree->nil)
4990             node = node->left;
4991           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4992                                                     &iter,
4993                                                     &parent);
4994           depth++;
4995
4996           /* Sanity Check! */
4997           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4998         }
4999       else
5000         {
5001           gboolean done = FALSE;
5002
5003           do
5004             {
5005               node = _gtk_rbtree_next (tree, node);
5006               if (node != NULL)
5007                 {
5008                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5009                   done = TRUE;
5010
5011                   /* Sanity Check! */
5012                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5013                 }
5014               else
5015                 {
5016                   GtkTreeIter parent_iter = iter;
5017                   gboolean has_parent;
5018
5019                   node = tree->parent_node;
5020                   tree = tree->parent_tree;
5021                   if (tree == NULL)
5022                     /* we should go to done to free some memory */
5023                     goto done;
5024                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5025                                                            &iter,
5026                                                            &parent_iter);
5027                   depth--;
5028
5029                   /* Sanity check */
5030                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5031                 }
5032             }
5033           while (!done);
5034         }
5035     }
5036   while (y_offset < event->area.height);
5037
5038 done:
5039   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
5040
5041   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5042     {
5043       GdkRectangle rectangle;
5044       gint n_rectangles;
5045  
5046       n_rectangles = cairo_region_num_rectangles (event->region);
5047  
5048       while (n_rectangles--)
5049         {
5050           cairo_region_get_rectangle (event->region, n_rectangles, &rectangle);
5051           gtk_tree_view_paint_rubber_band (tree_view, &rectangle);
5052         }
5053     }
5054
5055   if (cursor_path)
5056     gtk_tree_path_free (cursor_path);
5057
5058   if (drag_dest_path)
5059     gtk_tree_path_free (drag_dest_path);
5060
5061   return FALSE;
5062 }
5063
5064 static gboolean
5065 gtk_tree_view_expose (GtkWidget      *widget,
5066                       GdkEventExpose *event)
5067 {
5068   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5069
5070   if (event->window == tree_view->priv->bin_window)
5071     {
5072       gboolean retval;
5073       GList *tmp_list;
5074
5075       retval = gtk_tree_view_bin_expose (widget, event);
5076
5077       /* We can't just chain up to Container::expose as it will try to send the
5078        * event to the headers, so we handle propagating it to our children
5079        * (eg. widgets being edited) ourselves.
5080        */
5081       tmp_list = tree_view->priv->children;
5082       while (tmp_list)
5083         {
5084           GtkTreeViewChild *child = tmp_list->data;
5085           tmp_list = tmp_list->next;
5086
5087           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
5088         }
5089
5090       return retval;
5091     }
5092
5093   else if (event->window == tree_view->priv->header_window)
5094     {
5095       GList *list;
5096       
5097       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5098         {
5099           GtkTreeViewColumn *column = list->data;
5100
5101           if (column == tree_view->priv->drag_column)
5102             continue;
5103
5104           if (column->visible)
5105             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5106                                             column->button,
5107                                             event);
5108         }
5109     }
5110   else if (event->window == tree_view->priv->drag_window)
5111     {
5112       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5113                                       tree_view->priv->drag_column->button,
5114                                       event);
5115     }
5116   return TRUE;
5117 }
5118
5119 enum
5120 {
5121   DROP_HOME,
5122   DROP_RIGHT,
5123   DROP_LEFT,
5124   DROP_END
5125 };
5126
5127 /* returns 0x1 when no column has been found -- yes it's hackish */
5128 static GtkTreeViewColumn *
5129 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5130                                GtkTreeViewColumn *column,
5131                                gint               drop_position)
5132 {
5133   GtkTreeViewColumn *left_column = NULL;
5134   GtkTreeViewColumn *cur_column = NULL;
5135   GList *tmp_list;
5136
5137   if (!column->reorderable)
5138     return (GtkTreeViewColumn *)0x1;
5139
5140   switch (drop_position)
5141     {
5142       case DROP_HOME:
5143         /* find first column where we can drop */
5144         tmp_list = tree_view->priv->columns;
5145         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5146           return (GtkTreeViewColumn *)0x1;
5147
5148         while (tmp_list)
5149           {
5150             g_assert (tmp_list);
5151
5152             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5153             tmp_list = tmp_list->next;
5154
5155             if (left_column && left_column->visible == FALSE)
5156               continue;
5157
5158             if (!tree_view->priv->column_drop_func)
5159               return left_column;
5160
5161             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5162               {
5163                 left_column = cur_column;
5164                 continue;
5165               }
5166
5167             return left_column;
5168           }
5169
5170         if (!tree_view->priv->column_drop_func)
5171           return left_column;
5172
5173         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5174           return left_column;
5175         else
5176           return (GtkTreeViewColumn *)0x1;
5177         break;
5178
5179       case DROP_RIGHT:
5180         /* find first column after column where we can drop */
5181         tmp_list = tree_view->priv->columns;
5182
5183         for (; tmp_list; tmp_list = tmp_list->next)
5184           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5185             break;
5186
5187         if (!tmp_list || !tmp_list->next)
5188           return (GtkTreeViewColumn *)0x1;
5189
5190         tmp_list = tmp_list->next;
5191         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5192         tmp_list = tmp_list->next;
5193
5194         while (tmp_list)
5195           {
5196             g_assert (tmp_list);
5197
5198             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5199             tmp_list = tmp_list->next;
5200
5201             if (left_column && left_column->visible == FALSE)
5202               {
5203                 left_column = cur_column;
5204                 if (tmp_list)
5205                   tmp_list = tmp_list->next;
5206                 continue;
5207               }
5208
5209             if (!tree_view->priv->column_drop_func)
5210               return left_column;
5211
5212             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5213               {
5214                 left_column = cur_column;
5215                 continue;
5216               }
5217
5218             return left_column;
5219           }
5220
5221         if (!tree_view->priv->column_drop_func)
5222           return left_column;
5223
5224         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5225           return left_column;
5226         else
5227           return (GtkTreeViewColumn *)0x1;
5228         break;
5229
5230       case DROP_LEFT:
5231         /* find first column before column where we can drop */
5232         tmp_list = tree_view->priv->columns;
5233
5234         for (; tmp_list; tmp_list = tmp_list->next)
5235           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5236             break;
5237
5238         if (!tmp_list || !tmp_list->prev)
5239           return (GtkTreeViewColumn *)0x1;
5240
5241         tmp_list = tmp_list->prev;
5242         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5243         tmp_list = tmp_list->prev;
5244
5245         while (tmp_list)
5246           {
5247             g_assert (tmp_list);
5248
5249             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5250
5251             if (left_column && !left_column->visible)
5252               {
5253                 /*if (!tmp_list->prev)
5254                   return (GtkTreeViewColumn *)0x1;
5255                   */
5256 /*
5257                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5258                 tmp_list = tmp_list->prev->prev;
5259                 continue;*/
5260
5261                 cur_column = left_column;
5262                 if (tmp_list)
5263                   tmp_list = tmp_list->prev;
5264                 continue;
5265               }
5266
5267             if (!tree_view->priv->column_drop_func)
5268               return left_column;
5269
5270             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5271               return left_column;
5272
5273             cur_column = left_column;
5274             tmp_list = tmp_list->prev;
5275           }
5276
5277         if (!tree_view->priv->column_drop_func)
5278           return NULL;
5279
5280         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5281           return NULL;
5282         else
5283           return (GtkTreeViewColumn *)0x1;
5284         break;
5285
5286       case DROP_END:
5287         /* same as DROP_HOME case, but doing it backwards */
5288         tmp_list = g_list_last (tree_view->priv->columns);
5289         cur_column = NULL;
5290
5291         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5292           return (GtkTreeViewColumn *)0x1;
5293
5294         while (tmp_list)
5295           {
5296             g_assert (tmp_list);
5297
5298             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5299
5300             if (left_column && !left_column->visible)
5301               {
5302                 cur_column = left_column;
5303                 tmp_list = tmp_list->prev;
5304               }
5305
5306             if (!tree_view->priv->column_drop_func)
5307               return left_column;
5308
5309             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5310               return left_column;
5311
5312             cur_column = left_column;
5313             tmp_list = tmp_list->prev;
5314           }
5315
5316         if (!tree_view->priv->column_drop_func)
5317           return NULL;
5318
5319         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5320           return NULL;
5321         else
5322           return (GtkTreeViewColumn *)0x1;
5323         break;
5324     }
5325
5326   return (GtkTreeViewColumn *)0x1;
5327 }
5328
5329 static gboolean
5330 gtk_tree_view_key_press (GtkWidget   *widget,
5331                          GdkEventKey *event)
5332 {
5333   GtkTreeView *tree_view = (GtkTreeView *) widget;
5334
5335   if (tree_view->priv->rubber_band_status)
5336     {
5337       if (event->keyval == GDK_KEY_Escape)
5338         gtk_tree_view_stop_rubber_band (tree_view);
5339
5340       return TRUE;
5341     }
5342
5343   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5344     {
5345       if (event->keyval == GDK_KEY_Escape)
5346         {
5347           tree_view->priv->cur_reorder = NULL;
5348           gtk_tree_view_button_release_drag_column (widget, NULL);
5349         }
5350       return TRUE;
5351     }
5352
5353   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5354     {
5355       GList *focus_column;
5356       gboolean rtl;
5357
5358       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5359
5360       for (focus_column = tree_view->priv->columns;
5361            focus_column;
5362            focus_column = focus_column->next)
5363         {
5364           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5365
5366           if (gtk_widget_has_focus (column->button))
5367             break;
5368         }
5369
5370       if (focus_column &&
5371           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5372           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5373            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5374         {
5375           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5376
5377           if (!column->resizable)
5378             {
5379               gtk_widget_error_bell (widget);
5380               return TRUE;
5381             }
5382
5383           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5384               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5385             {
5386               GtkRequisition button_req;
5387               gint old_width = column->resized_width;
5388
5389               gtk_size_request_get_size (GTK_SIZE_REQUEST (column->button), &button_req, NULL);
5390
5391               column->resized_width = MAX (column->resized_width,
5392                                            column->width);
5393               column->resized_width -= 2;
5394               if (column->resized_width < 0)
5395                 column->resized_width = 0;
5396
5397               if (column->min_width == -1)
5398                 column->resized_width = MAX (button_req.width,
5399                                              column->resized_width);
5400               else
5401                 {
5402                   column->resized_width = MAX (column->min_width,
5403                                                column->resized_width);
5404                 }
5405
5406               if (column->max_width != -1)
5407                 column->resized_width = MIN (column->resized_width,
5408                                              column->max_width);
5409
5410               column->use_resized_width = TRUE;
5411
5412               if (column->resized_width != old_width)
5413                 gtk_widget_queue_resize (widget);
5414               else
5415                 gtk_widget_error_bell (widget);
5416             }
5417           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5418                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5419             {
5420               gint old_width = column->resized_width;
5421
5422               column->resized_width = MAX (column->resized_width,
5423                                            column->width);
5424               column->resized_width += 2;
5425
5426               if (column->max_width != -1)
5427                 column->resized_width = MIN (column->resized_width,
5428                                              column->max_width);
5429
5430               column->use_resized_width = TRUE;
5431
5432               if (column->resized_width != old_width)
5433                 gtk_widget_queue_resize (widget);
5434               else
5435                 gtk_widget_error_bell (widget);
5436             }
5437
5438           return TRUE;
5439         }
5440
5441       if (focus_column &&
5442           (event->state & GDK_MOD1_MASK) &&
5443           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5444            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5445            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5446            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5447         {
5448           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5449
5450           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5451               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5452             {
5453               GtkTreeViewColumn *col;
5454               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5455               if (col != (GtkTreeViewColumn *)0x1)
5456                 gtk_tree_view_move_column_after (tree_view, column, col);
5457               else
5458                 gtk_widget_error_bell (widget);
5459             }
5460           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5461                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5462             {
5463               GtkTreeViewColumn *col;
5464               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5465               if (col != (GtkTreeViewColumn *)0x1)
5466                 gtk_tree_view_move_column_after (tree_view, column, col);
5467               else
5468                 gtk_widget_error_bell (widget);
5469             }
5470           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5471             {
5472               GtkTreeViewColumn *col;
5473               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5474               if (col != (GtkTreeViewColumn *)0x1)
5475                 gtk_tree_view_move_column_after (tree_view, column, col);
5476               else
5477                 gtk_widget_error_bell (widget);
5478             }
5479           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5480             {
5481               GtkTreeViewColumn *col;
5482               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5483               if (col != (GtkTreeViewColumn *)0x1)
5484                 gtk_tree_view_move_column_after (tree_view, column, col);
5485               else
5486                 gtk_widget_error_bell (widget);
5487             }
5488
5489           return TRUE;
5490         }
5491     }
5492
5493   /* Chain up to the parent class.  It handles the keybindings. */
5494   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5495     return TRUE;
5496
5497   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5498     {
5499       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5500       return FALSE;
5501     }
5502
5503   /* We pass the event to the search_entry.  If its text changes, then we start
5504    * the typeahead find capabilities. */
5505   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5506       && tree_view->priv->enable_search
5507       && !tree_view->priv->search_custom_entry_set)
5508     {
5509       GdkEvent *new_event;
5510       char *old_text;
5511       const char *new_text;
5512       gboolean retval;
5513       GdkScreen *screen;
5514       gboolean text_modified;
5515       gulong popup_menu_id;
5516
5517       gtk_tree_view_ensure_interactive_directory (tree_view);
5518
5519       /* Make a copy of the current text */
5520       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5521       new_event = gdk_event_copy ((GdkEvent *) event);
5522       g_object_unref (((GdkEventKey *) new_event)->window);
5523       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5524       gtk_widget_realize (tree_view->priv->search_window);
5525
5526       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5527                                         "popup-menu", G_CALLBACK (gtk_true),
5528                                         NULL);
5529
5530       /* Move the entry off screen */
5531       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5532       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5533                        gdk_screen_get_width (screen) + 1,
5534                        gdk_screen_get_height (screen) + 1);
5535       gtk_widget_show (tree_view->priv->search_window);
5536
5537       /* Send the event to the window.  If the preedit_changed signal is emitted
5538        * during this event, we will set priv->imcontext_changed  */
5539       tree_view->priv->imcontext_changed = FALSE;
5540       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5541       gdk_event_free (new_event);
5542       gtk_widget_hide (tree_view->priv->search_window);
5543
5544       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5545                                    popup_menu_id);
5546
5547       /* We check to make sure that the entry tried to handle the text, and that
5548        * the text has changed.
5549        */
5550       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5551       text_modified = strcmp (old_text, new_text) != 0;
5552       g_free (old_text);
5553       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5554           (retval && text_modified))               /* ...or the text was modified */
5555         {
5556           if (gtk_tree_view_real_start_interactive_search (tree_view,
5557                                                            gdk_event_get_device ((GdkEvent *) event),
5558                                                            FALSE))
5559             {
5560               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5561               return TRUE;
5562             }
5563           else
5564             {
5565               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5566               return FALSE;
5567             }
5568         }
5569     }
5570
5571   return FALSE;
5572 }
5573
5574 static gboolean
5575 gtk_tree_view_key_release (GtkWidget   *widget,
5576                            GdkEventKey *event)
5577 {
5578   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5579
5580   if (tree_view->priv->rubber_band_status)
5581     return TRUE;
5582
5583   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5584 }
5585
5586 /* FIXME Is this function necessary? Can I get an enter_notify event
5587  * w/o either an expose event or a mouse motion event?
5588  */
5589 static gboolean
5590 gtk_tree_view_enter_notify (GtkWidget        *widget,
5591                             GdkEventCrossing *event)
5592 {
5593   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5594   GtkRBTree *tree;
5595   GtkRBNode *node;
5596   gint new_y;
5597
5598   /* Sanity check it */
5599   if (event->window != tree_view->priv->bin_window)
5600     return FALSE;
5601
5602   if (tree_view->priv->tree == NULL)
5603     return FALSE;
5604
5605   if (event->mode == GDK_CROSSING_GRAB ||
5606       event->mode == GDK_CROSSING_GTK_GRAB ||
5607       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5608       event->mode == GDK_CROSSING_STATE_CHANGED)
5609     return TRUE;
5610
5611   /* find the node internally */
5612   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5613   if (new_y < 0)
5614     new_y = 0;
5615   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5616
5617   tree_view->priv->event_last_x = event->x;
5618   tree_view->priv->event_last_y = event->y;
5619
5620   if ((tree_view->priv->button_pressed_node == NULL) ||
5621       (tree_view->priv->button_pressed_node == node))
5622     prelight_or_select (tree_view, tree, node, event->x, event->y);
5623
5624   return TRUE;
5625 }
5626
5627 static gboolean
5628 gtk_tree_view_leave_notify (GtkWidget        *widget,
5629                             GdkEventCrossing *event)
5630 {
5631   GtkTreeView *tree_view;
5632
5633   if (event->mode == GDK_CROSSING_GRAB)
5634     return TRUE;
5635
5636   tree_view = GTK_TREE_VIEW (widget);
5637
5638   if (tree_view->priv->prelight_node)
5639     _gtk_tree_view_queue_draw_node (tree_view,
5640                                    tree_view->priv->prelight_tree,
5641                                    tree_view->priv->prelight_node,
5642                                    NULL);
5643
5644   tree_view->priv->event_last_x = -10000;
5645   tree_view->priv->event_last_y = -10000;
5646
5647   prelight_or_select (tree_view,
5648                       NULL, NULL,
5649                       -1000, -1000); /* coords not possibly over an arrow */
5650
5651   return TRUE;
5652 }
5653
5654
5655 static gint
5656 gtk_tree_view_focus_out (GtkWidget     *widget,
5657                          GdkEventFocus *event)
5658 {
5659   GtkTreeView *tree_view;
5660
5661   tree_view = GTK_TREE_VIEW (widget);
5662
5663   gtk_widget_queue_draw (widget);
5664
5665   /* destroy interactive search dialog */
5666   if (tree_view->priv->search_window)
5667     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5668                                       gdk_event_get_device ((GdkEvent *) event));
5669
5670   return FALSE;
5671 }
5672
5673
5674 /* Incremental Reflow
5675  */
5676
5677 static void
5678 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5679                                  GtkRBTree   *tree,
5680                                  GtkRBNode   *node)
5681 {
5682   GtkAllocation allocation;
5683   gint y;
5684
5685   y = _gtk_rbtree_node_find_offset (tree, node)
5686     - tree_view->priv->vadjustment->value
5687     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5688
5689   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5690   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5691                               0, y,
5692                               allocation.width,
5693                               GTK_RBNODE_GET_HEIGHT (node));
5694 }
5695
5696 static gboolean
5697 node_is_visible (GtkTreeView *tree_view,
5698                  GtkRBTree   *tree,
5699                  GtkRBNode   *node)
5700 {
5701   int y;
5702   int height;
5703
5704   y = _gtk_rbtree_node_find_offset (tree, node);
5705   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5706
5707   if (y >= tree_view->priv->vadjustment->value &&
5708       y + height <= (tree_view->priv->vadjustment->value
5709                      + tree_view->priv->vadjustment->page_size))
5710     return TRUE;
5711
5712   return FALSE;
5713 }
5714
5715 /* Returns TRUE if it updated the size
5716  */
5717 static gboolean
5718 validate_row (GtkTreeView *tree_view,
5719               GtkRBTree   *tree,
5720               GtkRBNode   *node,
5721               GtkTreeIter *iter,
5722               GtkTreePath *path)
5723 {
5724   GtkTreeViewColumn *column;
5725   GList *list, *first_column, *last_column;
5726   gint height = 0;
5727   gint horizontal_separator;
5728   gint vertical_separator;
5729   gint focus_line_width;
5730   gint depth = gtk_tree_path_get_depth (path);
5731   gboolean retval = FALSE;
5732   gboolean is_separator = FALSE;
5733   gboolean draw_vgrid_lines, draw_hgrid_lines;
5734   gint focus_pad;
5735   gint grid_line_width;
5736   gboolean wide_separators;
5737   gint separator_height;
5738
5739   /* double check the row needs validating */
5740   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5741       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5742     return FALSE;
5743
5744   is_separator = row_is_separator (tree_view, iter, NULL);
5745
5746   gtk_widget_style_get (GTK_WIDGET (tree_view),
5747                         "focus-padding", &focus_pad,
5748                         "focus-line-width", &focus_line_width,
5749                         "horizontal-separator", &horizontal_separator,
5750                         "vertical-separator", &vertical_separator,
5751                         "grid-line-width", &grid_line_width,
5752                         "wide-separators",  &wide_separators,
5753                         "separator-height", &separator_height,
5754                         NULL);
5755   
5756   draw_vgrid_lines =
5757     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5758     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5759   draw_hgrid_lines =
5760     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5761     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5762
5763   for (last_column = g_list_last (tree_view->priv->columns);
5764        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5765        last_column = last_column->prev)
5766     ;
5767
5768   for (first_column = g_list_first (tree_view->priv->columns);
5769        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5770        first_column = first_column->next)
5771     ;
5772
5773   for (list = tree_view->priv->columns; list; list = list->next)
5774     {
5775       gint tmp_width;
5776       gint tmp_height;
5777
5778       column = list->data;
5779
5780       if (! column->visible)
5781         continue;
5782
5783       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5784         continue;
5785
5786       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5787                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5788                                                node->children?TRUE:FALSE);
5789       gtk_tree_view_column_cell_get_size (column,
5790                                           NULL, NULL, NULL,
5791                                           &tmp_width, &tmp_height);
5792
5793       if (!is_separator)
5794         {
5795           tmp_height += vertical_separator;
5796           height = MAX (height, tmp_height);
5797           height = MAX (height, tree_view->priv->expander_size);
5798         }
5799       else
5800         {
5801           if (wide_separators)
5802             height = separator_height + 2 * focus_pad;
5803           else
5804             height = 2 + 2 * focus_pad;
5805         }
5806
5807       if (gtk_tree_view_is_expander_column (tree_view, column))
5808         {
5809           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5810
5811           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5812             tmp_width += depth * tree_view->priv->expander_size;
5813         }
5814       else
5815         tmp_width = tmp_width + horizontal_separator;
5816
5817       if (draw_vgrid_lines)
5818         {
5819           if (list->data == first_column || list->data == last_column)
5820             tmp_width += grid_line_width / 2.0;
5821           else
5822             tmp_width += grid_line_width;
5823         }
5824
5825       if (tmp_width > column->requested_width)
5826         {
5827           retval = TRUE;
5828           column->requested_width = tmp_width;
5829         }
5830     }
5831
5832   if (draw_hgrid_lines)
5833     height += grid_line_width;
5834
5835   if (height != GTK_RBNODE_GET_HEIGHT (node))
5836     {
5837       retval = TRUE;
5838       _gtk_rbtree_node_set_height (tree, node, height);
5839     }
5840   _gtk_rbtree_node_mark_valid (tree, node);
5841   tree_view->priv->post_validation_flag = TRUE;
5842
5843   return retval;
5844 }
5845
5846
5847 static void
5848 validate_visible_area (GtkTreeView *tree_view)
5849 {
5850   GtkAllocation allocation;
5851   GtkTreePath *path = NULL;
5852   GtkTreePath *above_path = NULL;
5853   GtkTreeIter iter;
5854   GtkRBTree *tree = NULL;
5855   GtkRBNode *node = NULL;
5856   gboolean need_redraw = FALSE;
5857   gboolean size_changed = FALSE;
5858   gint total_height;
5859   gint area_above = 0;
5860   gint area_below = 0;
5861
5862   if (tree_view->priv->tree == NULL)
5863     return;
5864
5865   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5866       tree_view->priv->scroll_to_path == NULL)
5867     return;
5868
5869   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5870   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5871
5872   if (total_height == 0)
5873     return;
5874
5875   /* First, we check to see if we need to scroll anywhere
5876    */
5877   if (tree_view->priv->scroll_to_path)
5878     {
5879       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5880       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5881         {
5882           /* we are going to scroll, and will update dy */
5883           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5884           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5885               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5886             {
5887               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5888               if (validate_row (tree_view, tree, node, &iter, path))
5889                 size_changed = TRUE;
5890             }
5891
5892           if (tree_view->priv->scroll_to_use_align)
5893             {
5894               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5895               area_above = (total_height - height) *
5896                 tree_view->priv->scroll_to_row_align;
5897               area_below = total_height - area_above - height;
5898               area_above = MAX (area_above, 0);
5899               area_below = MAX (area_below, 0);
5900             }
5901           else
5902             {
5903               /* two cases:
5904                * 1) row not visible
5905                * 2) row visible
5906                */
5907               gint dy;
5908               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5909
5910               dy = _gtk_rbtree_node_find_offset (tree, node);
5911
5912               if (dy >= tree_view->priv->vadjustment->value &&
5913                   dy + height <= (tree_view->priv->vadjustment->value
5914                                   + tree_view->priv->vadjustment->page_size))
5915                 {
5916                   /* row visible: keep the row at the same position */
5917                   area_above = dy - tree_view->priv->vadjustment->value;
5918                   area_below = (tree_view->priv->vadjustment->value +
5919                                 tree_view->priv->vadjustment->page_size)
5920                                - dy - height;
5921                 }
5922               else
5923                 {
5924                   /* row not visible */
5925                   if (dy >= 0
5926                       && dy + height <= tree_view->priv->vadjustment->page_size)
5927                     {
5928                       /* row at the beginning -- fixed */
5929                       area_above = dy;
5930                       area_below = tree_view->priv->vadjustment->page_size
5931                                    - area_above - height;
5932                     }
5933                   else if (dy >= (tree_view->priv->vadjustment->upper -
5934                                   tree_view->priv->vadjustment->page_size))
5935                     {
5936                       /* row at the end -- fixed */
5937                       area_above = dy - (tree_view->priv->vadjustment->upper -
5938                                    tree_view->priv->vadjustment->page_size);
5939                       area_below = tree_view->priv->vadjustment->page_size -
5940                                    area_above - height;
5941
5942                       if (area_below < 0)
5943                         {
5944                           area_above = tree_view->priv->vadjustment->page_size - height;
5945                           area_below = 0;
5946                         }
5947                     }
5948                   else
5949                     {
5950                       /* row somewhere in the middle, bring it to the top
5951                        * of the view
5952                        */
5953                       area_above = 0;
5954                       area_below = total_height - height;
5955                     }
5956                 }
5957             }
5958         }
5959       else
5960         /* the scroll to isn't valid; ignore it.
5961          */
5962         {
5963           if (tree_view->priv->scroll_to_path && !path)
5964             {
5965               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5966               tree_view->priv->scroll_to_path = NULL;
5967             }
5968           if (path)
5969             gtk_tree_path_free (path);
5970           path = NULL;
5971         }      
5972     }
5973
5974   /* We didn't have a scroll_to set, so we just handle things normally
5975    */
5976   if (path == NULL)
5977     {
5978       gint offset;
5979
5980       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5981                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5982                                         &tree, &node);
5983       if (node == NULL)
5984         {
5985           /* In this case, nothing has been validated */
5986           path = gtk_tree_path_new_first ();
5987           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5988         }
5989       else
5990         {
5991           path = _gtk_tree_view_find_path (tree_view, tree, node);
5992           total_height += offset;
5993         }
5994
5995       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5996
5997       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5998           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5999         {
6000           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6001           if (validate_row (tree_view, tree, node, &iter, path))
6002             size_changed = TRUE;
6003         }
6004       area_above = 0;
6005       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6006     }
6007
6008   above_path = gtk_tree_path_copy (path);
6009
6010   /* if we do not validate any row above the new top_row, we will make sure
6011    * that the row immediately above top_row has been validated. (if we do not
6012    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6013    * when invalidated that row's height will be zero. and this will mess up
6014    * scrolling).
6015    */
6016   if (area_above == 0)
6017     {
6018       GtkRBTree *tmptree;
6019       GtkRBNode *tmpnode;
6020
6021       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6022       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6023
6024       if (tmpnode)
6025         {
6026           GtkTreePath *tmppath;
6027           GtkTreeIter tmpiter;
6028
6029           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6030           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6031
6032           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6033               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6034             {
6035               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6036               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6037                 size_changed = TRUE;
6038             }
6039
6040           gtk_tree_path_free (tmppath);
6041         }
6042     }
6043
6044   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6045    * backwards is much slower then forward, as there is no iter_prev function.
6046    * We go forwards first in case we run out of tree.  Then we go backwards to
6047    * fill out the top.
6048    */
6049   while (node && area_below > 0)
6050     {
6051       if (node->children)
6052         {
6053           GtkTreeIter parent = iter;
6054           gboolean has_child;
6055
6056           tree = node->children;
6057           node = tree->root;
6058
6059           g_assert (node != tree->nil);
6060
6061           while (node->left != tree->nil)
6062             node = node->left;
6063           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6064                                                     &iter,
6065                                                     &parent);
6066           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6067           gtk_tree_path_down (path);
6068         }
6069       else
6070         {
6071           gboolean done = FALSE;
6072           do
6073             {
6074               node = _gtk_rbtree_next (tree, node);
6075               if (node != NULL)
6076                 {
6077                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6078                   done = TRUE;
6079                   gtk_tree_path_next (path);
6080
6081                   /* Sanity Check! */
6082                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6083                 }
6084               else
6085                 {
6086                   GtkTreeIter parent_iter = iter;
6087                   gboolean has_parent;
6088
6089                   node = tree->parent_node;
6090                   tree = tree->parent_tree;
6091                   if (tree == NULL)
6092                     break;
6093                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6094                                                            &iter,
6095                                                            &parent_iter);
6096                   gtk_tree_path_up (path);
6097
6098                   /* Sanity check */
6099                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6100                 }
6101             }
6102           while (!done);
6103         }
6104
6105       if (!node)
6106         break;
6107
6108       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6109           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6110         {
6111           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6112           if (validate_row (tree_view, tree, node, &iter, path))
6113               size_changed = TRUE;
6114         }
6115
6116       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6117     }
6118   gtk_tree_path_free (path);
6119
6120   /* If we ran out of tree, and have extra area_below left, we need to add it
6121    * to area_above */
6122   if (area_below > 0)
6123     area_above += area_below;
6124
6125   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6126
6127   /* We walk backwards */
6128   while (area_above > 0)
6129     {
6130       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6131
6132       /* Always find the new path in the tree.  We cannot just assume
6133        * a gtk_tree_path_prev() is enough here, as there might be children
6134        * in between this node and the previous sibling node.  If this
6135        * appears to be a performance hotspot in profiles, we can look into
6136        * intrigate logic for keeping path, node and iter in sync like
6137        * we do for forward walks.  (Which will be hard because of the lacking
6138        * iter_prev).
6139        */
6140
6141       if (node == NULL)
6142         break;
6143
6144       gtk_tree_path_free (above_path);
6145       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6146
6147       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6148
6149       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6150           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6151         {
6152           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6153           if (validate_row (tree_view, tree, node, &iter, above_path))
6154             size_changed = TRUE;
6155         }
6156       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6157     }
6158
6159   /* if we scrolled to a path, we need to set the dy here,
6160    * and sync the top row accordingly
6161    */
6162   if (tree_view->priv->scroll_to_path)
6163     {
6164       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6165       gtk_tree_view_top_row_to_dy (tree_view);
6166
6167       need_redraw = TRUE;
6168     }
6169   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6170     {
6171       /* when we are not scrolling, we should never set dy to something
6172        * else than zero. we update top_row to be in sync with dy = 0.
6173        */
6174       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6175       gtk_tree_view_dy_to_top_row (tree_view);
6176     }
6177   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6178     {
6179       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6180       gtk_tree_view_dy_to_top_row (tree_view);
6181     }
6182   else
6183     gtk_tree_view_top_row_to_dy (tree_view);
6184
6185   /* update width/height and queue a resize */
6186   if (size_changed)
6187     {
6188       GtkRequisition requisition;
6189
6190       /* We temporarily guess a size, under the assumption that it will be the
6191        * same when we get our next size_allocate.  If we don't do this, we'll be
6192        * in an inconsistent state if we call top_row_to_dy. */
6193
6194       gtk_size_request_get_size (GTK_SIZE_REQUEST (tree_view),
6195                                  &requisition, NULL);
6196       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6197       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6198       gtk_adjustment_changed (tree_view->priv->hadjustment);
6199       gtk_adjustment_changed (tree_view->priv->vadjustment);
6200       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6201     }
6202
6203   if (tree_view->priv->scroll_to_path)
6204     {
6205       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6206       tree_view->priv->scroll_to_path = NULL;
6207     }
6208
6209   if (above_path)
6210     gtk_tree_path_free (above_path);
6211
6212   if (tree_view->priv->scroll_to_column)
6213     {
6214       tree_view->priv->scroll_to_column = NULL;
6215     }
6216   if (need_redraw)
6217     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6218 }
6219
6220 static void
6221 initialize_fixed_height_mode (GtkTreeView *tree_view)
6222 {
6223   if (!tree_view->priv->tree)
6224     return;
6225
6226   if (tree_view->priv->fixed_height < 0)
6227     {
6228       GtkTreeIter iter;
6229       GtkTreePath *path;
6230
6231       GtkRBTree *tree = NULL;
6232       GtkRBNode *node = NULL;
6233
6234       tree = tree_view->priv->tree;
6235       node = tree->root;
6236
6237       path = _gtk_tree_view_find_path (tree_view, tree, node);
6238       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6239
6240       validate_row (tree_view, tree, node, &iter, path);
6241
6242       gtk_tree_path_free (path);
6243
6244       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6245     }
6246
6247    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6248                                  tree_view->priv->fixed_height, TRUE);
6249 }
6250
6251 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6252  * the left-most uninvalidated node.  We then try walking right, validating
6253  * nodes.  Once we find a valid node, we repeat the previous process of finding
6254  * the first invalid node.
6255  */
6256
6257 static gboolean
6258 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6259 {
6260   GtkRBTree *tree = NULL;
6261   GtkRBNode *node = NULL;
6262   gboolean validated_area = FALSE;
6263   gint retval = TRUE;
6264   GtkTreePath *path = NULL;
6265   GtkTreeIter iter;
6266   GTimer *timer;
6267   gint i = 0;
6268
6269   gint prev_height = -1;
6270   gboolean fixed_height = TRUE;
6271
6272   g_assert (tree_view);
6273
6274   if (tree_view->priv->tree == NULL)
6275       return FALSE;
6276
6277   if (tree_view->priv->fixed_height_mode)
6278     {
6279       if (tree_view->priv->fixed_height < 0)
6280         initialize_fixed_height_mode (tree_view);
6281
6282       return FALSE;
6283     }
6284
6285   timer = g_timer_new ();
6286   g_timer_start (timer);
6287
6288   do
6289     {
6290       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6291         {
6292           retval = FALSE;
6293           goto done;
6294         }
6295
6296       if (path != NULL)
6297         {
6298           node = _gtk_rbtree_next (tree, node);
6299           if (node != NULL)
6300             {
6301               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6302               gtk_tree_path_next (path);
6303             }
6304           else
6305             {
6306               gtk_tree_path_free (path);
6307               path = NULL;
6308             }
6309         }
6310
6311       if (path == NULL)
6312         {
6313           tree = tree_view->priv->tree;
6314           node = tree_view->priv->tree->root;
6315
6316           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6317
6318           do
6319             {
6320               if (node->left != tree->nil &&
6321                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6322                 {
6323                   node = node->left;
6324                 }
6325               else if (node->right != tree->nil &&
6326                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6327                 {
6328                   node = node->right;
6329                 }
6330               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6331                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6332                 {
6333                   break;
6334                 }
6335               else if (node->children != NULL)
6336                 {
6337                   tree = node->children;
6338                   node = tree->root;
6339                 }
6340               else
6341                 /* RBTree corruption!  All bad */
6342                 g_assert_not_reached ();
6343             }
6344           while (TRUE);
6345           path = _gtk_tree_view_find_path (tree_view, tree, node);
6346           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6347         }
6348
6349       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6350                        validated_area;
6351
6352       if (!tree_view->priv->fixed_height_check)
6353         {
6354           gint height;
6355
6356           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6357           if (prev_height < 0)
6358             prev_height = height;
6359           else if (prev_height != height)
6360             fixed_height = FALSE;
6361         }
6362
6363       i++;
6364     }
6365   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6366
6367   if (!tree_view->priv->fixed_height_check)
6368    {
6369      if (fixed_height)
6370        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6371
6372      tree_view->priv->fixed_height_check = 1;
6373    }
6374   
6375  done:
6376   if (validated_area)
6377     {
6378       GtkRequisition requisition;
6379       /* We temporarily guess a size, under the assumption that it will be the
6380        * same when we get our next size_allocate.  If we don't do this, we'll be
6381        * in an inconsistent state when we call top_row_to_dy. */
6382
6383       gtk_size_request_get_size (GTK_SIZE_REQUEST (tree_view),
6384                                  &requisition, NULL);
6385       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6386       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6387       gtk_adjustment_changed (tree_view->priv->hadjustment);
6388       gtk_adjustment_changed (tree_view->priv->vadjustment);
6389
6390       if (queue_resize)
6391         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6392     }
6393
6394   if (path) gtk_tree_path_free (path);
6395   g_timer_destroy (timer);
6396
6397   return retval;
6398 }
6399
6400 static gboolean
6401 validate_rows (GtkTreeView *tree_view)
6402 {
6403   gboolean retval;
6404   
6405   retval = do_validate_rows (tree_view, TRUE);
6406   
6407   if (! retval && tree_view->priv->validate_rows_timer)
6408     {
6409       g_source_remove (tree_view->priv->validate_rows_timer);
6410       tree_view->priv->validate_rows_timer = 0;
6411     }
6412
6413   return retval;
6414 }
6415
6416 static gboolean
6417 validate_rows_handler (GtkTreeView *tree_view)
6418 {
6419   gboolean retval;
6420
6421   retval = do_validate_rows (tree_view, TRUE);
6422   if (! retval && tree_view->priv->validate_rows_timer)
6423     {
6424       g_source_remove (tree_view->priv->validate_rows_timer);
6425       tree_view->priv->validate_rows_timer = 0;
6426     }
6427
6428   return retval;
6429 }
6430
6431 static gboolean
6432 do_presize_handler (GtkTreeView *tree_view)
6433 {
6434   if (tree_view->priv->mark_rows_col_dirty)
6435     {
6436       if (tree_view->priv->tree)
6437         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6438       tree_view->priv->mark_rows_col_dirty = FALSE;
6439     }
6440   validate_visible_area (tree_view);
6441   tree_view->priv->presize_handler_timer = 0;
6442
6443   if (tree_view->priv->fixed_height_mode)
6444     {
6445       GtkRequisition requisition;
6446
6447       gtk_size_request_get_size (GTK_SIZE_REQUEST (tree_view),
6448                                  &requisition, NULL);
6449
6450       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6451       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6452       gtk_adjustment_changed (tree_view->priv->hadjustment);
6453       gtk_adjustment_changed (tree_view->priv->vadjustment);
6454       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6455     }
6456                    
6457   return FALSE;
6458 }
6459
6460 static gboolean
6461 presize_handler_callback (gpointer data)
6462 {
6463   do_presize_handler (GTK_TREE_VIEW (data));
6464                    
6465   return FALSE;
6466 }
6467
6468 static void
6469 install_presize_handler (GtkTreeView *tree_view)
6470 {
6471   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6472     return;
6473
6474   if (! tree_view->priv->presize_handler_timer)
6475     {
6476       tree_view->priv->presize_handler_timer =
6477         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6478     }
6479   if (! tree_view->priv->validate_rows_timer)
6480     {
6481       tree_view->priv->validate_rows_timer =
6482         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6483     }
6484 }
6485
6486 static gboolean
6487 scroll_sync_handler (GtkTreeView *tree_view)
6488 {
6489   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6490     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6491   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6492     gtk_tree_view_top_row_to_dy (tree_view);
6493   else
6494     gtk_tree_view_dy_to_top_row (tree_view);
6495
6496   tree_view->priv->scroll_sync_timer = 0;
6497
6498   return FALSE;
6499 }
6500
6501 static void
6502 install_scroll_sync_handler (GtkTreeView *tree_view)
6503 {
6504   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6505     return;
6506
6507   if (!tree_view->priv->scroll_sync_timer)
6508     {
6509       tree_view->priv->scroll_sync_timer =
6510         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6511     }
6512 }
6513
6514 static void
6515 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6516                            GtkTreePath *path,
6517                            gint         offset)
6518 {
6519   gtk_tree_row_reference_free (tree_view->priv->top_row);
6520
6521   if (!path)
6522     {
6523       tree_view->priv->top_row = NULL;
6524       tree_view->priv->top_row_dy = 0;
6525     }
6526   else
6527     {
6528       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6529       tree_view->priv->top_row_dy = offset;
6530     }
6531 }
6532
6533 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6534  * it's set to be NULL, and top_row_dy is 0;
6535  */
6536 static void
6537 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6538 {
6539   gint offset;
6540   GtkTreePath *path;
6541   GtkRBTree *tree;
6542   GtkRBNode *node;
6543
6544   if (tree_view->priv->tree == NULL)
6545     {
6546       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6547     }
6548   else
6549     {
6550       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6551                                         tree_view->priv->dy,
6552                                         &tree, &node);
6553
6554       if (tree == NULL)
6555         {
6556           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6557         }
6558       else
6559         {
6560           path = _gtk_tree_view_find_path (tree_view, tree, node);
6561           gtk_tree_view_set_top_row (tree_view, path, offset);
6562           gtk_tree_path_free (path);
6563         }
6564     }
6565 }
6566
6567 static void
6568 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6569 {
6570   GtkTreePath *path;
6571   GtkRBTree *tree;
6572   GtkRBNode *node;
6573   int new_dy;
6574
6575   /* Avoid recursive calls */
6576   if (tree_view->priv->in_top_row_to_dy)
6577     return;
6578
6579   if (tree_view->priv->top_row)
6580     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6581   else
6582     path = NULL;
6583
6584   if (!path)
6585     tree = NULL;
6586   else
6587     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6588
6589   if (path)
6590     gtk_tree_path_free (path);
6591
6592   if (tree == NULL)
6593     {
6594       /* keep dy and set new toprow */
6595       gtk_tree_row_reference_free (tree_view->priv->top_row);
6596       tree_view->priv->top_row = NULL;
6597       tree_view->priv->top_row_dy = 0;
6598       /* DO NOT install the idle handler */
6599       gtk_tree_view_dy_to_top_row (tree_view);
6600       return;
6601     }
6602
6603   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6604       < tree_view->priv->top_row_dy)
6605     {
6606       /* new top row -- do NOT install the idle handler */
6607       gtk_tree_view_dy_to_top_row (tree_view);
6608       return;
6609     }
6610
6611   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6612   new_dy += tree_view->priv->top_row_dy;
6613
6614   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6615     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6616
6617   new_dy = MAX (0, new_dy);
6618
6619   tree_view->priv->in_top_row_to_dy = TRUE;
6620   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6621   tree_view->priv->in_top_row_to_dy = FALSE;
6622 }
6623
6624
6625 void
6626 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6627 {
6628   tree_view->priv->mark_rows_col_dirty = TRUE;
6629
6630   install_presize_handler (tree_view);
6631 }
6632
6633 /*
6634  * This function works synchronously (due to the while (validate_rows...)
6635  * loop).
6636  *
6637  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6638  * here. You now need to check that yourself.
6639  */
6640 void
6641 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6642                                 GtkTreeViewColumn *column)
6643 {
6644   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6645   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6646
6647   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6648
6649   do_presize_handler (tree_view);
6650   while (validate_rows (tree_view));
6651
6652   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6653 }
6654
6655 /* Drag-and-drop */
6656
6657 static void
6658 set_source_row (GdkDragContext *context,
6659                 GtkTreeModel   *model,
6660                 GtkTreePath    *source_row)
6661 {
6662   g_object_set_data_full (G_OBJECT (context),
6663                           I_("gtk-tree-view-source-row"),
6664                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6665                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6666 }
6667
6668 static GtkTreePath*
6669 get_source_row (GdkDragContext *context)
6670 {
6671   GtkTreeRowReference *ref =
6672     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6673
6674   if (ref)
6675     return gtk_tree_row_reference_get_path (ref);
6676   else
6677     return NULL;
6678 }
6679
6680 typedef struct
6681 {
6682   GtkTreeRowReference *dest_row;
6683   guint                path_down_mode   : 1;
6684   guint                empty_view_drop  : 1;
6685   guint                drop_append_mode : 1;
6686 }
6687 DestRow;
6688
6689 static void
6690 dest_row_free (gpointer data)
6691 {
6692   DestRow *dr = (DestRow *)data;
6693
6694   gtk_tree_row_reference_free (dr->dest_row);
6695   g_slice_free (DestRow, dr);
6696 }
6697
6698 static void
6699 set_dest_row (GdkDragContext *context,
6700               GtkTreeModel   *model,
6701               GtkTreePath    *dest_row,
6702               gboolean        path_down_mode,
6703               gboolean        empty_view_drop,
6704               gboolean        drop_append_mode)
6705 {
6706   DestRow *dr;
6707
6708   if (!dest_row)
6709     {
6710       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6711                               NULL, NULL);
6712       return;
6713     }
6714
6715   dr = g_slice_new (DestRow);
6716
6717   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6718   dr->path_down_mode = path_down_mode != FALSE;
6719   dr->empty_view_drop = empty_view_drop != FALSE;
6720   dr->drop_append_mode = drop_append_mode != FALSE;
6721
6722   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6723                           dr, (GDestroyNotify) dest_row_free);
6724 }
6725
6726 static GtkTreePath*
6727 get_dest_row (GdkDragContext *context,
6728               gboolean       *path_down_mode)
6729 {
6730   DestRow *dr =
6731     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6732
6733   if (dr)
6734     {
6735       GtkTreePath *path = NULL;
6736
6737       if (path_down_mode)
6738         *path_down_mode = dr->path_down_mode;
6739
6740       if (dr->dest_row)
6741         path = gtk_tree_row_reference_get_path (dr->dest_row);
6742       else if (dr->empty_view_drop)
6743         path = gtk_tree_path_new_from_indices (0, -1);
6744       else
6745         path = NULL;
6746
6747       if (path && dr->drop_append_mode)
6748         gtk_tree_path_next (path);
6749
6750       return path;
6751     }
6752   else
6753     return NULL;
6754 }
6755
6756 /* Get/set whether drag_motion requested the drag data and
6757  * drag_data_received should thus not actually insert the data,
6758  * since the data doesn't result from a drop.
6759  */
6760 static void
6761 set_status_pending (GdkDragContext *context,
6762                     GdkDragAction   suggested_action)
6763 {
6764   g_object_set_data (G_OBJECT (context),
6765                      I_("gtk-tree-view-status-pending"),
6766                      GINT_TO_POINTER (suggested_action));
6767 }
6768
6769 static GdkDragAction
6770 get_status_pending (GdkDragContext *context)
6771 {
6772   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6773                                              "gtk-tree-view-status-pending"));
6774 }
6775
6776 static TreeViewDragInfo*
6777 get_info (GtkTreeView *tree_view)
6778 {
6779   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6780 }
6781
6782 static void
6783 destroy_info (TreeViewDragInfo *di)
6784 {
6785   g_slice_free (TreeViewDragInfo, di);
6786 }
6787
6788 static TreeViewDragInfo*
6789 ensure_info (GtkTreeView *tree_view)
6790 {
6791   TreeViewDragInfo *di;
6792
6793   di = get_info (tree_view);
6794
6795   if (di == NULL)
6796     {
6797       di = g_slice_new0 (TreeViewDragInfo);
6798
6799       g_object_set_data_full (G_OBJECT (tree_view),
6800                               I_("gtk-tree-view-drag-info"),
6801                               di,
6802                               (GDestroyNotify) destroy_info);
6803     }
6804
6805   return di;
6806 }
6807
6808 static void
6809 remove_info (GtkTreeView *tree_view)
6810 {
6811   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6812 }
6813
6814 #if 0
6815 static gint
6816 drag_scan_timeout (gpointer data)
6817 {
6818   GtkTreeView *tree_view;
6819   gint x, y;
6820   GdkModifierType state;
6821   GtkTreePath *path = NULL;
6822   GtkTreeViewColumn *column = NULL;
6823   GdkRectangle visible_rect;
6824
6825   GDK_THREADS_ENTER ();
6826
6827   tree_view = GTK_TREE_VIEW (data);
6828
6829   gdk_window_get_pointer (tree_view->priv->bin_window,
6830                           &x, &y, &state);
6831
6832   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6833
6834   /* See if we are near the edge. */
6835   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6836       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6837       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6838       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6839     {
6840       gtk_tree_view_get_path_at_pos (tree_view,
6841                                      tree_view->priv->bin_window,
6842                                      x, y,
6843                                      &path,
6844                                      &column,
6845                                      NULL,
6846                                      NULL);
6847
6848       if (path != NULL)
6849         {
6850           gtk_tree_view_scroll_to_cell (tree_view,
6851                                         path,
6852                                         column,
6853                                         TRUE,
6854                                         0.5, 0.5);
6855
6856           gtk_tree_path_free (path);
6857         }
6858     }
6859
6860   GDK_THREADS_LEAVE ();
6861
6862   return TRUE;
6863 }
6864 #endif /* 0 */
6865
6866 static void
6867 add_scroll_timeout (GtkTreeView *tree_view)
6868 {
6869   if (tree_view->priv->scroll_timeout == 0)
6870     {
6871       tree_view->priv->scroll_timeout =
6872         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6873     }
6874 }
6875
6876 static void
6877 remove_scroll_timeout (GtkTreeView *tree_view)
6878 {
6879   if (tree_view->priv->scroll_timeout != 0)
6880     {
6881       g_source_remove (tree_view->priv->scroll_timeout);
6882       tree_view->priv->scroll_timeout = 0;
6883     }
6884 }
6885
6886 static gboolean
6887 check_model_dnd (GtkTreeModel *model,
6888                  GType         required_iface,
6889                  const gchar  *signal)
6890 {
6891   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6892     {
6893       g_warning ("You must override the default '%s' handler "
6894                  "on GtkTreeView when using models that don't support "
6895                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6896                  "is to connect to '%s' and call "
6897                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6898                  "the default handler from running. Look at the source code "
6899                  "for the default handler in gtktreeview.c to get an idea what "
6900                  "your handler should do. (gtktreeview.c is in the GTK source "
6901                  "code.) If you're using GTK from a language other than C, "
6902                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6903                  signal, g_type_name (required_iface), signal);
6904       return FALSE;
6905     }
6906   else
6907     return TRUE;
6908 }
6909
6910 static void
6911 remove_open_timeout (GtkTreeView *tree_view)
6912 {
6913   if (tree_view->priv->open_dest_timeout != 0)
6914     {
6915       g_source_remove (tree_view->priv->open_dest_timeout);
6916       tree_view->priv->open_dest_timeout = 0;
6917     }
6918 }
6919
6920
6921 static gint
6922 open_row_timeout (gpointer data)
6923 {
6924   GtkTreeView *tree_view = data;
6925   GtkTreePath *dest_path = NULL;
6926   GtkTreeViewDropPosition pos;
6927   gboolean result = FALSE;
6928
6929   gtk_tree_view_get_drag_dest_row (tree_view,
6930                                    &dest_path,
6931                                    &pos);
6932
6933   if (dest_path &&
6934       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6935        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6936     {
6937       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6938       tree_view->priv->open_dest_timeout = 0;
6939
6940       gtk_tree_path_free (dest_path);
6941     }
6942   else
6943     {
6944       if (dest_path)
6945         gtk_tree_path_free (dest_path);
6946
6947       result = TRUE;
6948     }
6949
6950   return result;
6951 }
6952
6953 static gboolean
6954 scroll_row_timeout (gpointer data)
6955 {
6956   GtkTreeView *tree_view = data;
6957
6958   gtk_tree_view_vertical_autoscroll (tree_view);
6959
6960   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6961     gtk_tree_view_update_rubber_band (tree_view);
6962
6963   return TRUE;
6964 }
6965
6966 /* Returns TRUE if event should not be propagated to parent widgets */
6967 static gboolean
6968 set_destination_row (GtkTreeView    *tree_view,
6969                      GdkDragContext *context,
6970                      /* coordinates relative to the widget */
6971                      gint            x,
6972                      gint            y,
6973                      GdkDragAction  *suggested_action,
6974                      GdkAtom        *target)
6975 {
6976   GtkTreePath *path = NULL;
6977   GtkTreeViewDropPosition pos;
6978   GtkTreeViewDropPosition old_pos;
6979   TreeViewDragInfo *di;
6980   GtkWidget *widget;
6981   GtkTreePath *old_dest_path = NULL;
6982   gboolean can_drop = FALSE;
6983
6984   *suggested_action = 0;
6985   *target = GDK_NONE;
6986
6987   widget = GTK_WIDGET (tree_view);
6988
6989   di = get_info (tree_view);
6990
6991   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6992     {
6993       /* someone unset us as a drag dest, note that if
6994        * we return FALSE drag_leave isn't called
6995        */
6996
6997       gtk_tree_view_set_drag_dest_row (tree_view,
6998                                        NULL,
6999                                        GTK_TREE_VIEW_DROP_BEFORE);
7000
7001       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7002       remove_open_timeout (GTK_TREE_VIEW (widget));
7003
7004       return FALSE; /* no longer a drop site */
7005     }
7006
7007   *target = gtk_drag_dest_find_target (widget, context,
7008                                        gtk_drag_dest_get_target_list (widget));
7009   if (*target == GDK_NONE)
7010     {
7011       return FALSE;
7012     }
7013
7014   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7015                                           x, y,
7016                                           &path,
7017                                           &pos))
7018     {
7019       gint n_children;
7020       GtkTreeModel *model;
7021
7022       remove_open_timeout (tree_view);
7023
7024       /* the row got dropped on empty space, let's setup a special case
7025        */
7026
7027       if (path)
7028         gtk_tree_path_free (path);
7029
7030       model = gtk_tree_view_get_model (tree_view);
7031
7032       n_children = gtk_tree_model_iter_n_children (model, NULL);
7033       if (n_children)
7034         {
7035           pos = GTK_TREE_VIEW_DROP_AFTER;
7036           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7037         }
7038       else
7039         {
7040           pos = GTK_TREE_VIEW_DROP_BEFORE;
7041           path = gtk_tree_path_new_from_indices (0, -1);
7042         }
7043
7044       can_drop = TRUE;
7045
7046       goto out;
7047     }
7048
7049   g_assert (path);
7050
7051   /* If we left the current row's "open" zone, unset the timeout for
7052    * opening the row
7053    */
7054   gtk_tree_view_get_drag_dest_row (tree_view,
7055                                    &old_dest_path,
7056                                    &old_pos);
7057
7058   if (old_dest_path &&
7059       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7060        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7061          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7062     remove_open_timeout (tree_view);
7063
7064   if (old_dest_path)
7065     gtk_tree_path_free (old_dest_path);
7066
7067   if (TRUE /* FIXME if the location droppable predicate */)
7068     {
7069       can_drop = TRUE;
7070     }
7071
7072 out:
7073   if (can_drop)
7074     {
7075       GtkWidget *source_widget;
7076
7077       *suggested_action = context->suggested_action;
7078       source_widget = gtk_drag_get_source_widget (context);
7079
7080       if (source_widget == widget)
7081         {
7082           /* Default to MOVE, unless the user has
7083            * pressed ctrl or shift to affect available actions
7084            */
7085           if ((context->actions & GDK_ACTION_MOVE) != 0)
7086             *suggested_action = GDK_ACTION_MOVE;
7087         }
7088
7089       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7090                                        path, pos);
7091     }
7092   else
7093     {
7094       /* can't drop here */
7095       remove_open_timeout (tree_view);
7096
7097       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7098                                        NULL,
7099                                        GTK_TREE_VIEW_DROP_BEFORE);
7100     }
7101
7102   if (path)
7103     gtk_tree_path_free (path);
7104
7105   return TRUE;
7106 }
7107
7108 static GtkTreePath*
7109 get_logical_dest_row (GtkTreeView *tree_view,
7110                       gboolean    *path_down_mode,
7111                       gboolean    *drop_append_mode)
7112 {
7113   /* adjust path to point to the row the drop goes in front of */
7114   GtkTreePath *path = NULL;
7115   GtkTreeViewDropPosition pos;
7116
7117   g_return_val_if_fail (path_down_mode != NULL, NULL);
7118   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7119
7120   *path_down_mode = FALSE;
7121   *drop_append_mode = 0;
7122
7123   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7124
7125   if (path == NULL)
7126     return NULL;
7127
7128   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7129     ; /* do nothing */
7130   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7131            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7132     *path_down_mode = TRUE;
7133   else
7134     {
7135       GtkTreeIter iter;
7136       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7137
7138       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7139
7140       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7141           !gtk_tree_model_iter_next (model, &iter))
7142         *drop_append_mode = 1;
7143       else
7144         {
7145           *drop_append_mode = 0;
7146           gtk_tree_path_next (path);
7147         }
7148     }
7149
7150   return path;
7151 }
7152
7153 static gboolean
7154 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7155                                         GdkEventMotion   *event)
7156 {
7157   GtkWidget *widget = GTK_WIDGET (tree_view);
7158   GdkDragContext *context;
7159   TreeViewDragInfo *di;
7160   GtkTreePath *path = NULL;
7161   gint button;
7162   gint cell_x, cell_y;
7163   GtkTreeModel *model;
7164   gboolean retval = FALSE;
7165
7166   di = get_info (tree_view);
7167
7168   if (di == NULL || !di->source_set)
7169     goto out;
7170
7171   if (tree_view->priv->pressed_button < 0)
7172     goto out;
7173
7174   if (!gtk_drag_check_threshold (widget,
7175                                  tree_view->priv->press_start_x,
7176                                  tree_view->priv->press_start_y,
7177                                  event->x, event->y))
7178     goto out;
7179
7180   model = gtk_tree_view_get_model (tree_view);
7181
7182   if (model == NULL)
7183     goto out;
7184
7185   button = tree_view->priv->pressed_button;
7186   tree_view->priv->pressed_button = -1;
7187
7188   gtk_tree_view_get_path_at_pos (tree_view,
7189                                  tree_view->priv->press_start_x,
7190                                  tree_view->priv->press_start_y,
7191                                  &path,
7192                                  NULL,
7193                                  &cell_x,
7194                                  &cell_y);
7195
7196   if (path == NULL)
7197     goto out;
7198
7199   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7200       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7201                                            path))
7202     goto out;
7203
7204   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7205     goto out;
7206
7207   /* Now we can begin the drag */
7208
7209   retval = TRUE;
7210
7211   context = gtk_drag_begin (widget,
7212                             gtk_drag_source_get_target_list (widget),
7213                             di->source_actions,
7214                             button,
7215                             (GdkEvent*)event);
7216
7217   set_source_row (context, model, path);
7218
7219  out:
7220   if (path)
7221     gtk_tree_path_free (path);
7222
7223   return retval;
7224 }
7225
7226
7227 static void
7228 gtk_tree_view_drag_begin (GtkWidget      *widget,
7229                           GdkDragContext *context)
7230 {
7231   GtkTreeView *tree_view;
7232   GtkTreePath *path = NULL;
7233   gint cell_x, cell_y;
7234   GdkPixmap *row_pix;
7235   TreeViewDragInfo *di;
7236
7237   tree_view = GTK_TREE_VIEW (widget);
7238
7239   /* if the user uses a custom DND source impl, we don't set the icon here */
7240   di = get_info (tree_view);
7241
7242   if (di == NULL || !di->source_set)
7243     return;
7244
7245   gtk_tree_view_get_path_at_pos (tree_view,
7246                                  tree_view->priv->press_start_x,
7247                                  tree_view->priv->press_start_y,
7248                                  &path,
7249                                  NULL,
7250                                  &cell_x,
7251                                  &cell_y);
7252
7253   g_return_if_fail (path != NULL);
7254
7255   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7256                                                 path);
7257
7258   gtk_drag_set_icon_pixmap (context,
7259                             gdk_drawable_get_colormap (row_pix),
7260                             row_pix,
7261                             NULL,
7262                             /* the + 1 is for the black border in the icon */
7263                             tree_view->priv->press_start_x + 1,
7264                             cell_y + 1);
7265
7266   g_object_unref (row_pix);
7267   gtk_tree_path_free (path);
7268 }
7269
7270 static void
7271 gtk_tree_view_drag_end (GtkWidget      *widget,
7272                         GdkDragContext *context)
7273 {
7274   /* do nothing */
7275 }
7276
7277 /* Default signal implementations for the drag signals */
7278 static void
7279 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7280                              GdkDragContext   *context,
7281                              GtkSelectionData *selection_data,
7282                              guint             info,
7283                              guint             time)
7284 {
7285   GtkTreeView *tree_view;
7286   GtkTreeModel *model;
7287   TreeViewDragInfo *di;
7288   GtkTreePath *source_row;
7289
7290   tree_view = GTK_TREE_VIEW (widget);
7291
7292   model = gtk_tree_view_get_model (tree_view);
7293
7294   if (model == NULL)
7295     return;
7296
7297   di = get_info (GTK_TREE_VIEW (widget));
7298
7299   if (di == NULL)
7300     return;
7301
7302   source_row = get_source_row (context);
7303
7304   if (source_row == NULL)
7305     return;
7306
7307   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7308    * any model; for DragSource models there are some other targets
7309    * we also support.
7310    */
7311
7312   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7313       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7314                                           source_row,
7315                                           selection_data))
7316     goto done;
7317
7318   /* If drag_data_get does nothing, try providing row data. */
7319   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7320     {
7321       gtk_tree_set_row_drag_data (selection_data,
7322                                   model,
7323                                   source_row);
7324     }
7325
7326  done:
7327   gtk_tree_path_free (source_row);
7328 }
7329
7330
7331 static void
7332 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7333                                 GdkDragContext *context)
7334 {
7335   TreeViewDragInfo *di;
7336   GtkTreeModel *model;
7337   GtkTreeView *tree_view;
7338   GtkTreePath *source_row;
7339
7340   tree_view = GTK_TREE_VIEW (widget);
7341   model = gtk_tree_view_get_model (tree_view);
7342
7343   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7344     return;
7345
7346   di = get_info (tree_view);
7347
7348   if (di == NULL)
7349     return;
7350
7351   source_row = get_source_row (context);
7352
7353   if (source_row == NULL)
7354     return;
7355
7356   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7357                                          source_row);
7358
7359   gtk_tree_path_free (source_row);
7360
7361   set_source_row (context, NULL, NULL);
7362 }
7363
7364 static void
7365 gtk_tree_view_drag_leave (GtkWidget      *widget,
7366                           GdkDragContext *context,
7367                           guint             time)
7368 {
7369   /* unset any highlight row */
7370   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7371                                    NULL,
7372                                    GTK_TREE_VIEW_DROP_BEFORE);
7373
7374   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7375   remove_open_timeout (GTK_TREE_VIEW (widget));
7376 }
7377
7378
7379 static gboolean
7380 gtk_tree_view_drag_motion (GtkWidget        *widget,
7381                            GdkDragContext   *context,
7382                            /* coordinates relative to the widget */
7383                            gint              x,
7384                            gint              y,
7385                            guint             time)
7386 {
7387   gboolean empty;
7388   GtkTreePath *path = NULL;
7389   GtkTreeViewDropPosition pos;
7390   GtkTreeView *tree_view;
7391   GdkDragAction suggested_action = 0;
7392   GdkAtom target;
7393
7394   tree_view = GTK_TREE_VIEW (widget);
7395
7396   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7397     return FALSE;
7398
7399   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7400
7401   /* we only know this *after* set_desination_row */
7402   empty = tree_view->priv->empty_view_drop;
7403
7404   if (path == NULL && !empty)
7405     {
7406       /* Can't drop here. */
7407       gdk_drag_status (context, 0, time);
7408     }
7409   else
7410     {
7411       if (tree_view->priv->open_dest_timeout == 0 &&
7412           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7413            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7414         {
7415           tree_view->priv->open_dest_timeout =
7416             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7417         }
7418       else
7419         {
7420           add_scroll_timeout (tree_view);
7421         }
7422
7423       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7424         {
7425           /* Request data so we can use the source row when
7426            * determining whether to accept the drop
7427            */
7428           set_status_pending (context, suggested_action);
7429           gtk_drag_get_data (widget, context, target, time);
7430         }
7431       else
7432         {
7433           set_status_pending (context, 0);
7434           gdk_drag_status (context, suggested_action, time);
7435         }
7436     }
7437
7438   if (path)
7439     gtk_tree_path_free (path);
7440
7441   return TRUE;
7442 }
7443
7444
7445 static gboolean
7446 gtk_tree_view_drag_drop (GtkWidget        *widget,
7447                          GdkDragContext   *context,
7448                          /* coordinates relative to the widget */
7449                          gint              x,
7450                          gint              y,
7451                          guint             time)
7452 {
7453   GtkTreeView *tree_view;
7454   GtkTreePath *path;
7455   GdkDragAction suggested_action = 0;
7456   GdkAtom target = GDK_NONE;
7457   TreeViewDragInfo *di;
7458   GtkTreeModel *model;
7459   gboolean path_down_mode;
7460   gboolean drop_append_mode;
7461
7462   tree_view = GTK_TREE_VIEW (widget);
7463
7464   model = gtk_tree_view_get_model (tree_view);
7465
7466   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7467   remove_open_timeout (GTK_TREE_VIEW (widget));
7468
7469   di = get_info (tree_view);
7470
7471   if (di == NULL)
7472     return FALSE;
7473
7474   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7475     return FALSE;
7476
7477   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7478     return FALSE;
7479
7480   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7481
7482   if (target != GDK_NONE && path != NULL)
7483     {
7484       /* in case a motion had requested drag data, change things so we
7485        * treat drag data receives as a drop.
7486        */
7487       set_status_pending (context, 0);
7488       set_dest_row (context, model, path,
7489                     path_down_mode, tree_view->priv->empty_view_drop,
7490                     drop_append_mode);
7491     }
7492
7493   if (path)
7494     gtk_tree_path_free (path);
7495
7496   /* Unset this thing */
7497   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7498                                    NULL,
7499                                    GTK_TREE_VIEW_DROP_BEFORE);
7500
7501   if (target != GDK_NONE)
7502     {
7503       gtk_drag_get_data (widget, context, target, time);
7504       return TRUE;
7505     }
7506   else
7507     return FALSE;
7508 }
7509
7510 static void
7511 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7512                                   GdkDragContext   *context,
7513                                   /* coordinates relative to the widget */
7514                                   gint              x,
7515                                   gint              y,
7516                                   GtkSelectionData *selection_data,
7517                                   guint             info,
7518                                   guint             time)
7519 {
7520   GtkTreePath *path;
7521   TreeViewDragInfo *di;
7522   gboolean accepted = FALSE;
7523   GtkTreeModel *model;
7524   GtkTreeView *tree_view;
7525   GtkTreePath *dest_row;
7526   GdkDragAction suggested_action;
7527   gboolean path_down_mode;
7528   gboolean drop_append_mode;
7529
7530   tree_view = GTK_TREE_VIEW (widget);
7531
7532   model = gtk_tree_view_get_model (tree_view);
7533
7534   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7535     return;
7536
7537   di = get_info (tree_view);
7538
7539   if (di == NULL)
7540     return;
7541
7542   suggested_action = get_status_pending (context);
7543
7544   if (suggested_action)
7545     {
7546       /* We are getting this data due to a request in drag_motion,
7547        * rather than due to a request in drag_drop, so we are just
7548        * supposed to call drag_status, not actually paste in the
7549        * data.
7550        */
7551       path = get_logical_dest_row (tree_view, &path_down_mode,
7552                                    &drop_append_mode);
7553
7554       if (path == NULL)
7555         suggested_action = 0;
7556       else if (path_down_mode)
7557         gtk_tree_path_down (path);
7558
7559       if (suggested_action)
7560         {
7561           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7562                                                      path,
7563                                                      selection_data))
7564             {
7565               if (path_down_mode)
7566                 {
7567                   path_down_mode = FALSE;
7568                   gtk_tree_path_up (path);
7569
7570                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7571                                                              path,
7572                                                              selection_data))
7573                     suggested_action = 0;
7574                 }
7575               else
7576                 suggested_action = 0;
7577             }
7578         }
7579
7580       gdk_drag_status (context, suggested_action, time);
7581
7582       if (path)
7583         gtk_tree_path_free (path);
7584
7585       /* If you can't drop, remove user drop indicator until the next motion */
7586       if (suggested_action == 0)
7587         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7588                                          NULL,
7589                                          GTK_TREE_VIEW_DROP_BEFORE);
7590
7591       return;
7592     }
7593
7594   dest_row = get_dest_row (context, &path_down_mode);
7595
7596   if (dest_row == NULL)
7597     return;
7598
7599   if (selection_data->length >= 0)
7600     {
7601       if (path_down_mode)
7602         {
7603           gtk_tree_path_down (dest_row);
7604           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7605                                                      dest_row, selection_data))
7606             gtk_tree_path_up (dest_row);
7607         }
7608     }
7609
7610   if (selection_data->length >= 0)
7611     {
7612       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7613                                                  dest_row,
7614                                                  selection_data))
7615         accepted = TRUE;
7616     }
7617
7618   gtk_drag_finish (context,
7619                    accepted,
7620                    (context->action == GDK_ACTION_MOVE),
7621                    time);
7622
7623   if (gtk_tree_path_get_depth (dest_row) == 1
7624       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7625     {
7626       /* special special case drag to "0", scroll to first item */
7627       if (!tree_view->priv->scroll_to_path)
7628         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7629     }
7630
7631   gtk_tree_path_free (dest_row);
7632
7633   /* drop dest_row */
7634   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7635 }
7636
7637
7638
7639 /* GtkContainer Methods
7640  */
7641
7642
7643 static void
7644 gtk_tree_view_remove (GtkContainer *container,
7645                       GtkWidget    *widget)
7646 {
7647   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7648   GtkTreeViewChild *child = NULL;
7649   GList *tmp_list;
7650
7651   tmp_list = tree_view->priv->children;
7652   while (tmp_list)
7653     {
7654       child = tmp_list->data;
7655       if (child->widget == widget)
7656         {
7657           gtk_widget_unparent (widget);
7658
7659           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7660           g_list_free_1 (tmp_list);
7661           g_slice_free (GtkTreeViewChild, child);
7662           return;
7663         }
7664
7665       tmp_list = tmp_list->next;
7666     }
7667
7668   tmp_list = tree_view->priv->columns;
7669
7670   while (tmp_list)
7671     {
7672       GtkTreeViewColumn *column;
7673       column = tmp_list->data;
7674       if (column->button == widget)
7675         {
7676           gtk_widget_unparent (widget);
7677           return;
7678         }
7679       tmp_list = tmp_list->next;
7680     }
7681 }
7682
7683 static void
7684 gtk_tree_view_forall (GtkContainer *container,
7685                       gboolean      include_internals,
7686                       GtkCallback   callback,
7687                       gpointer      callback_data)
7688 {
7689   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7690   GtkTreeViewChild *child = NULL;
7691   GtkTreeViewColumn *column;
7692   GList *tmp_list;
7693
7694   tmp_list = tree_view->priv->children;
7695   while (tmp_list)
7696     {
7697       child = tmp_list->data;
7698       tmp_list = tmp_list->next;
7699
7700       (* callback) (child->widget, callback_data);
7701     }
7702   if (include_internals == FALSE)
7703     return;
7704
7705   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7706     {
7707       column = tmp_list->data;
7708
7709       if (column->button)
7710         (* callback) (column->button, callback_data);
7711     }
7712 }
7713
7714 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7715  * cells. If so we draw one big row-spanning focus rectangle.
7716  */
7717 static gboolean
7718 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7719 {
7720   GList *list;
7721
7722   for (list = tree_view->priv->columns; list; list = list->next)
7723     {
7724       if (!((GtkTreeViewColumn *)list->data)->visible)
7725         continue;
7726       if (_gtk_tree_view_column_count_special_cells (list->data))
7727         return TRUE;
7728     }
7729
7730   return FALSE;
7731 }
7732
7733 static void
7734 column_sizing_notify (GObject    *object,
7735                       GParamSpec *pspec,
7736                       gpointer    data)
7737 {
7738   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7739
7740   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7741     /* disable fixed height mode */
7742     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7743 }
7744
7745 /**
7746  * gtk_tree_view_set_fixed_height_mode:
7747  * @tree_view: a #GtkTreeView 
7748  * @enable: %TRUE to enable fixed height mode
7749  * 
7750  * Enables or disables the fixed height mode of @tree_view. 
7751  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7752  * rows have the same height. 
7753  * Only enable this option if all rows are the same height and all
7754  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7755  *
7756  * Since: 2.6 
7757  **/
7758 void
7759 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7760                                      gboolean     enable)
7761 {
7762   GList *l;
7763   
7764   enable = enable != FALSE;
7765
7766   if (enable == tree_view->priv->fixed_height_mode)
7767     return;
7768
7769   if (!enable)
7770     {
7771       tree_view->priv->fixed_height_mode = 0;
7772       tree_view->priv->fixed_height = -1;
7773
7774       /* force a revalidation */
7775       install_presize_handler (tree_view);
7776     }
7777   else 
7778     {
7779       /* make sure all columns are of type FIXED */
7780       for (l = tree_view->priv->columns; l; l = l->next)
7781         {
7782           GtkTreeViewColumn *c = l->data;
7783           
7784           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7785         }
7786       
7787       /* yes, we really have to do this is in a separate loop */
7788       for (l = tree_view->priv->columns; l; l = l->next)
7789         g_signal_connect (l->data, "notify::sizing",
7790                           G_CALLBACK (column_sizing_notify), tree_view);
7791       
7792       tree_view->priv->fixed_height_mode = 1;
7793       tree_view->priv->fixed_height = -1;
7794       
7795       if (tree_view->priv->tree)
7796         initialize_fixed_height_mode (tree_view);
7797     }
7798
7799   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7800 }
7801
7802 /**
7803  * gtk_tree_view_get_fixed_height_mode:
7804  * @tree_view: a #GtkTreeView
7805  * 
7806  * Returns whether fixed height mode is turned on for @tree_view.
7807  * 
7808  * Return value: %TRUE if @tree_view is in fixed height mode
7809  * 
7810  * Since: 2.6
7811  **/
7812 gboolean
7813 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7814 {
7815   return tree_view->priv->fixed_height_mode;
7816 }
7817
7818 /* Returns TRUE if the focus is within the headers, after the focus operation is
7819  * done
7820  */
7821 static gboolean
7822 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7823                             GtkDirectionType  dir,
7824                             gboolean          clamp_column_visible)
7825 {
7826   GtkWidget *focus_child;
7827
7828   GList *last_column, *first_column;
7829   GList *tmp_list;
7830   gboolean rtl;
7831
7832   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7833     return FALSE;
7834
7835   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7836
7837   first_column = tree_view->priv->columns;
7838   while (first_column)
7839     {
7840       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7841           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7842           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7843            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7844         break;
7845       first_column = first_column->next;
7846     }
7847
7848   /* No headers are visible, or are focusable.  We can't focus in or out.
7849    */
7850   if (first_column == NULL)
7851     return FALSE;
7852
7853   last_column = g_list_last (tree_view->priv->columns);
7854   while (last_column)
7855     {
7856       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7857           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7858           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7859            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7860         break;
7861       last_column = last_column->prev;
7862     }
7863
7864
7865   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7866
7867   switch (dir)
7868     {
7869     case GTK_DIR_TAB_BACKWARD:
7870     case GTK_DIR_TAB_FORWARD:
7871     case GTK_DIR_UP:
7872     case GTK_DIR_DOWN:
7873       if (focus_child == NULL)
7874         {
7875           if (tree_view->priv->focus_column != NULL &&
7876               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7877             focus_child = tree_view->priv->focus_column->button;
7878           else
7879             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7880           gtk_widget_grab_focus (focus_child);
7881           break;
7882         }
7883       return FALSE;
7884
7885     case GTK_DIR_LEFT:
7886     case GTK_DIR_RIGHT:
7887       if (focus_child == NULL)
7888         {
7889           if (tree_view->priv->focus_column != NULL)
7890             focus_child = tree_view->priv->focus_column->button;
7891           else if (dir == GTK_DIR_LEFT)
7892             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7893           else
7894             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7895           gtk_widget_grab_focus (focus_child);
7896           break;
7897         }
7898
7899       if (gtk_widget_child_focus (focus_child, dir))
7900         {
7901           /* The focus moves inside the button. */
7902           /* This is probably a great example of bad UI */
7903           break;
7904         }
7905
7906       /* We need to move the focus among the row of buttons. */
7907       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7908         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7909           break;
7910
7911       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7912           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7913         {
7914           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7915           break;
7916         }
7917
7918       while (tmp_list)
7919         {
7920           GtkTreeViewColumn *column;
7921
7922           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7923             tmp_list = tmp_list->next;
7924           else
7925             tmp_list = tmp_list->prev;
7926
7927           if (tmp_list == NULL)
7928             {
7929               g_warning ("Internal button not found");
7930               break;
7931             }
7932           column = tmp_list->data;
7933           if (column->button &&
7934               column->visible &&
7935               gtk_widget_get_can_focus (column->button))
7936             {
7937               focus_child = column->button;
7938               gtk_widget_grab_focus (column->button);
7939               break;
7940             }
7941         }
7942       break;
7943     default:
7944       g_assert_not_reached ();
7945       break;
7946     }
7947
7948   /* if focus child is non-null, we assume it's been set to the current focus child
7949    */
7950   if (focus_child)
7951     {
7952       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7953         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7954           {
7955             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7956             break;
7957           }
7958
7959       if (clamp_column_visible)
7960         {
7961           gtk_tree_view_clamp_column_visible (tree_view,
7962                                               tree_view->priv->focus_column,
7963                                               FALSE);
7964         }
7965     }
7966
7967   return (focus_child != NULL);
7968 }
7969
7970 /* This function returns in 'path' the first focusable path, if the given path
7971  * is already focusable, it's the returned one.
7972  */
7973 static gboolean
7974 search_first_focusable_path (GtkTreeView  *tree_view,
7975                              GtkTreePath **path,
7976                              gboolean      search_forward,
7977                              GtkRBTree   **new_tree,
7978                              GtkRBNode   **new_node)
7979 {
7980   GtkRBTree *tree = NULL;
7981   GtkRBNode *node = NULL;
7982
7983   if (!path || !*path)
7984     return FALSE;
7985
7986   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7987
7988   if (!tree || !node)
7989     return FALSE;
7990
7991   while (node && row_is_separator (tree_view, NULL, *path))
7992     {
7993       if (search_forward)
7994         _gtk_rbtree_next_full (tree, node, &tree, &node);
7995       else
7996         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7997
7998       if (*path)
7999         gtk_tree_path_free (*path);
8000
8001       if (node)
8002         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8003       else
8004         *path = NULL;
8005     }
8006
8007   if (new_tree)
8008     *new_tree = tree;
8009
8010   if (new_node)
8011     *new_node = node;
8012
8013   return (*path != NULL);
8014 }
8015
8016 static gint
8017 gtk_tree_view_focus (GtkWidget        *widget,
8018                      GtkDirectionType  direction)
8019 {
8020   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8021   GtkContainer *container = GTK_CONTAINER (widget);
8022   GtkWidget *focus_child;
8023
8024   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8025     return FALSE;
8026
8027   focus_child = gtk_container_get_focus_child (container);
8028
8029   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8030   /* Case 1.  Headers currently have focus. */
8031   if (focus_child)
8032     {
8033       switch (direction)
8034         {
8035         case GTK_DIR_LEFT:
8036         case GTK_DIR_RIGHT:
8037           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8038           return TRUE;
8039         case GTK_DIR_TAB_BACKWARD:
8040         case GTK_DIR_UP:
8041           return FALSE;
8042         case GTK_DIR_TAB_FORWARD:
8043         case GTK_DIR_DOWN:
8044           gtk_widget_grab_focus (widget);
8045           return TRUE;
8046         default:
8047           g_assert_not_reached ();
8048           return FALSE;
8049         }
8050     }
8051
8052   /* Case 2. We don't have focus at all. */
8053   if (!gtk_widget_has_focus (widget))
8054     {
8055       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
8056         gtk_widget_grab_focus (widget);
8057       return TRUE;
8058     }
8059
8060   /* Case 3. We have focus already. */
8061   if (direction == GTK_DIR_TAB_BACKWARD)
8062     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8063   else if (direction == GTK_DIR_TAB_FORWARD)
8064     return FALSE;
8065
8066   /* Other directions caught by the keybindings */
8067   gtk_widget_grab_focus (widget);
8068   return TRUE;
8069 }
8070
8071 static void
8072 gtk_tree_view_grab_focus (GtkWidget *widget)
8073 {
8074   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8075
8076   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8077 }
8078
8079 static void
8080 gtk_tree_view_style_set (GtkWidget *widget,
8081                          GtkStyle *previous_style)
8082 {
8083   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8084   GtkStyle *style;
8085   GList *list;
8086   GtkTreeViewColumn *column;
8087
8088   if (gtk_widget_get_realized (widget))
8089     {
8090       gdk_window_set_back_pixmap (gtk_widget_get_window (widget), NULL, FALSE);
8091       style = gtk_widget_get_style (widget);
8092       gdk_window_set_background (tree_view->priv->bin_window,
8093                                  &style->base[gtk_widget_get_state (widget)]);
8094       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8095
8096       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8097       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8098     }
8099
8100   gtk_widget_style_get (widget,
8101                         "expander-size", &tree_view->priv->expander_size,
8102                         NULL);
8103   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8104
8105   for (list = tree_view->priv->columns; list; list = list->next)
8106     {
8107       column = list->data;
8108       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8109     }
8110
8111   tree_view->priv->fixed_height = -1;
8112   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8113
8114   gtk_widget_queue_resize (widget);
8115 }
8116
8117
8118 static void
8119 gtk_tree_view_set_focus_child (GtkContainer *container,
8120                                GtkWidget    *child)
8121 {
8122   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8123   GList *list;
8124
8125   for (list = tree_view->priv->columns; list; list = list->next)
8126     {
8127       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8128         {
8129           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8130           break;
8131         }
8132     }
8133
8134   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8135 }
8136
8137 static void
8138 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
8139                                GtkAdjustment *hadj,
8140                                GtkAdjustment *vadj)
8141 {
8142   gboolean need_adjust = FALSE;
8143
8144   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8145
8146   if (hadj)
8147     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
8148   else
8149     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8150   if (vadj)
8151     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
8152   else
8153     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8154
8155   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8156     {
8157       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8158                                             gtk_tree_view_adjustment_changed,
8159                                             tree_view);
8160       g_object_unref (tree_view->priv->hadjustment);
8161     }
8162
8163   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8164     {
8165       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8166                                             gtk_tree_view_adjustment_changed,
8167                                             tree_view);
8168       g_object_unref (tree_view->priv->vadjustment);
8169     }
8170
8171   if (tree_view->priv->hadjustment != hadj)
8172     {
8173       tree_view->priv->hadjustment = hadj;
8174       g_object_ref_sink (tree_view->priv->hadjustment);
8175
8176       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8177                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8178                         tree_view);
8179       need_adjust = TRUE;
8180     }
8181
8182   if (tree_view->priv->vadjustment != vadj)
8183     {
8184       tree_view->priv->vadjustment = vadj;
8185       g_object_ref_sink (tree_view->priv->vadjustment);
8186
8187       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8188                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8189                         tree_view);
8190       need_adjust = TRUE;
8191     }
8192
8193   if (need_adjust)
8194     gtk_tree_view_adjustment_changed (NULL, tree_view);
8195 }
8196
8197
8198 static gboolean
8199 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8200                                 GtkMovementStep    step,
8201                                 gint               count)
8202 {
8203   GdkModifierType state;
8204
8205   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8206   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8207                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8208                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8209                         step == GTK_MOVEMENT_PAGES ||
8210                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8211
8212   if (tree_view->priv->tree == NULL)
8213     return FALSE;
8214   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8215     return FALSE;
8216
8217   gtk_tree_view_stop_editing (tree_view, FALSE);
8218   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8219   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8220
8221   if (gtk_get_current_event_state (&state))
8222     {
8223       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8224         tree_view->priv->ctrl_pressed = TRUE;
8225       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8226         tree_view->priv->shift_pressed = TRUE;
8227     }
8228   /* else we assume not pressed */
8229
8230   switch (step)
8231     {
8232       /* currently we make no distinction.  When we go bi-di, we need to */
8233     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8234     case GTK_MOVEMENT_VISUAL_POSITIONS:
8235       gtk_tree_view_move_cursor_left_right (tree_view, count);
8236       break;
8237     case GTK_MOVEMENT_DISPLAY_LINES:
8238       gtk_tree_view_move_cursor_up_down (tree_view, count);
8239       break;
8240     case GTK_MOVEMENT_PAGES:
8241       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8242       break;
8243     case GTK_MOVEMENT_BUFFER_ENDS:
8244       gtk_tree_view_move_cursor_start_end (tree_view, count);
8245       break;
8246     default:
8247       g_assert_not_reached ();
8248     }
8249
8250   tree_view->priv->ctrl_pressed = FALSE;
8251   tree_view->priv->shift_pressed = FALSE;
8252
8253   return TRUE;
8254 }
8255
8256 static void
8257 gtk_tree_view_put (GtkTreeView *tree_view,
8258                    GtkWidget   *child_widget,
8259                    /* in bin_window coordinates */
8260                    gint         x,
8261                    gint         y,
8262                    gint         width,
8263                    gint         height)
8264 {
8265   GtkTreeViewChild *child;
8266   
8267   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8268   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8269
8270   child = g_slice_new (GtkTreeViewChild);
8271
8272   child->widget = child_widget;
8273   child->x = x;
8274   child->y = y;
8275   child->width = width;
8276   child->height = height;
8277
8278   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8279
8280   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8281     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8282   
8283   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8284 }
8285
8286 void
8287 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8288                                   GtkWidget   *widget,
8289                                   /* in tree coordinates */
8290                                   gint         x,
8291                                   gint         y,
8292                                   gint         width,
8293                                   gint         height)
8294 {
8295   GtkTreeViewChild *child = NULL;
8296   GList *list;
8297   GdkRectangle allocation;
8298
8299   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8300   g_return_if_fail (GTK_IS_WIDGET (widget));
8301
8302   for (list = tree_view->priv->children; list; list = list->next)
8303     {
8304       if (((GtkTreeViewChild *)list->data)->widget == widget)
8305         {
8306           child = list->data;
8307           break;
8308         }
8309     }
8310   if (child == NULL)
8311     return;
8312
8313   allocation.x = child->x = x;
8314   allocation.y = child->y = y;
8315   allocation.width = child->width = width;
8316   allocation.height = child->height = height;
8317
8318   if (gtk_widget_get_realized (widget))
8319     gtk_widget_size_allocate (widget, &allocation);
8320 }
8321
8322
8323 /* TreeModel Callbacks
8324  */
8325
8326 static void
8327 gtk_tree_view_row_changed (GtkTreeModel *model,
8328                            GtkTreePath  *path,
8329                            GtkTreeIter  *iter,
8330                            gpointer      data)
8331 {
8332   GtkTreeView *tree_view = (GtkTreeView *)data;
8333   GtkRBTree *tree;
8334   GtkRBNode *node;
8335   gboolean free_path = FALSE;
8336   GList *list;
8337   GtkTreePath *cursor_path;
8338
8339   g_return_if_fail (path != NULL || iter != NULL);
8340
8341   if (tree_view->priv->cursor != NULL)
8342     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8343   else
8344     cursor_path = NULL;
8345
8346   if (tree_view->priv->edited_column &&
8347       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8348     gtk_tree_view_stop_editing (tree_view, TRUE);
8349
8350   if (cursor_path != NULL)
8351     gtk_tree_path_free (cursor_path);
8352
8353   if (path == NULL)
8354     {
8355       path = gtk_tree_model_get_path (model, iter);
8356       free_path = TRUE;
8357     }
8358   else if (iter == NULL)
8359     gtk_tree_model_get_iter (model, iter, path);
8360
8361   if (_gtk_tree_view_find_node (tree_view,
8362                                 path,
8363                                 &tree,
8364                                 &node))
8365     /* We aren't actually showing the node */
8366     goto done;
8367
8368   if (tree == NULL)
8369     goto done;
8370
8371   if (tree_view->priv->fixed_height_mode
8372       && tree_view->priv->fixed_height >= 0)
8373     {
8374       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8375       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8376         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8377     }
8378   else
8379     {
8380       _gtk_rbtree_node_mark_invalid (tree, node);
8381       for (list = tree_view->priv->columns; list; list = list->next)
8382         {
8383           GtkTreeViewColumn *column;
8384
8385           column = list->data;
8386           if (! column->visible)
8387             continue;
8388
8389           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8390             {
8391               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8392             }
8393         }
8394     }
8395
8396  done:
8397   if (!tree_view->priv->fixed_height_mode &&
8398       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8399     install_presize_handler (tree_view);
8400   if (free_path)
8401     gtk_tree_path_free (path);
8402 }
8403
8404 static void
8405 gtk_tree_view_row_inserted (GtkTreeModel *model,
8406                             GtkTreePath  *path,
8407                             GtkTreeIter  *iter,
8408                             gpointer      data)
8409 {
8410   GtkTreeView *tree_view = (GtkTreeView *) data;
8411   gint *indices;
8412   GtkRBTree *tmptree, *tree;
8413   GtkRBNode *tmpnode = NULL;
8414   gint depth;
8415   gint i = 0;
8416   gint height;
8417   gboolean free_path = FALSE;
8418   gboolean node_visible = TRUE;
8419
8420   g_return_if_fail (path != NULL || iter != NULL);
8421
8422   if (tree_view->priv->fixed_height_mode
8423       && tree_view->priv->fixed_height >= 0)
8424     height = tree_view->priv->fixed_height;
8425   else
8426     height = 0;
8427
8428   if (path == NULL)
8429     {
8430       path = gtk_tree_model_get_path (model, iter);
8431       free_path = TRUE;
8432     }
8433   else if (iter == NULL)
8434     gtk_tree_model_get_iter (model, iter, path);
8435
8436   if (tree_view->priv->tree == NULL)
8437     tree_view->priv->tree = _gtk_rbtree_new ();
8438
8439   tmptree = tree = tree_view->priv->tree;
8440
8441   /* Update all row-references */
8442   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8443   depth = gtk_tree_path_get_depth (path);
8444   indices = gtk_tree_path_get_indices (path);
8445
8446   /* First, find the parent tree */
8447   while (i < depth - 1)
8448     {
8449       if (tmptree == NULL)
8450         {
8451           /* We aren't showing the node */
8452           node_visible = FALSE;
8453           goto done;
8454         }
8455
8456       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8457       if (tmpnode == NULL)
8458         {
8459           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8460                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8461                      "before the parent was inserted.");
8462           goto done;
8463         }
8464       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8465         {
8466           /* FIXME enforce correct behavior on model, probably */
8467           /* In theory, the model should have emitted has_child_toggled here.  We
8468            * try to catch it anyway, just to be safe, in case the model hasn't.
8469            */
8470           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8471                                                            tree,
8472                                                            tmpnode);
8473           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8474           gtk_tree_path_free (tmppath);
8475           goto done;
8476         }
8477
8478       tmptree = tmpnode->children;
8479       tree = tmptree;
8480       i++;
8481     }
8482
8483   if (tree == NULL)
8484     {
8485       node_visible = FALSE;
8486       goto done;
8487     }
8488
8489   /* ref the node */
8490   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8491   if (indices[depth - 1] == 0)
8492     {
8493       tmpnode = _gtk_rbtree_find_count (tree, 1);
8494       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8495     }
8496   else
8497     {
8498       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8499       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8500     }
8501
8502  done:
8503   if (height > 0)
8504     {
8505       if (tree)
8506         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8507
8508       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8509         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8510       else
8511         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8512     }
8513   else
8514     install_presize_handler (tree_view);
8515   if (free_path)
8516     gtk_tree_path_free (path);
8517 }
8518
8519 static void
8520 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8521                                      GtkTreePath  *path,
8522                                      GtkTreeIter  *iter,
8523                                      gpointer      data)
8524 {
8525   GtkTreeView *tree_view = (GtkTreeView *)data;
8526   GtkTreeIter real_iter;
8527   gboolean has_child;
8528   GtkRBTree *tree;
8529   GtkRBNode *node;
8530   gboolean free_path = FALSE;
8531
8532   g_return_if_fail (path != NULL || iter != NULL);
8533
8534   if (iter)
8535     real_iter = *iter;
8536
8537   if (path == NULL)
8538     {
8539       path = gtk_tree_model_get_path (model, iter);
8540       free_path = TRUE;
8541     }
8542   else if (iter == NULL)
8543     gtk_tree_model_get_iter (model, &real_iter, path);
8544
8545   if (_gtk_tree_view_find_node (tree_view,
8546                                 path,
8547                                 &tree,
8548                                 &node))
8549     /* We aren't actually showing the node */
8550     goto done;
8551
8552   if (tree == NULL)
8553     goto done;
8554
8555   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8556   /* Sanity check.
8557    */
8558   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8559     goto done;
8560
8561   if (has_child)
8562     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8563   else
8564     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8565
8566   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8567     {
8568       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8569       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8570         {
8571           GList *list;
8572
8573           for (list = tree_view->priv->columns; list; list = list->next)
8574             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8575               {
8576                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8577                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8578                 break;
8579               }
8580         }
8581       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8582     }
8583   else
8584     {
8585       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8586     }
8587
8588  done:
8589   if (free_path)
8590     gtk_tree_path_free (path);
8591 }
8592
8593 static void
8594 count_children_helper (GtkRBTree *tree,
8595                        GtkRBNode *node,
8596                        gpointer   data)
8597 {
8598   if (node->children)
8599     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8600   (*((gint *)data))++;
8601 }
8602
8603 static void
8604 check_selection_helper (GtkRBTree *tree,
8605                         GtkRBNode *node,
8606                         gpointer   data)
8607 {
8608   gint *value = (gint *)data;
8609
8610   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8611
8612   if (node->children && !*value)
8613     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8614 }
8615
8616 static void
8617 gtk_tree_view_row_deleted (GtkTreeModel *model,
8618                            GtkTreePath  *path,
8619                            gpointer      data)
8620 {
8621   GtkTreeView *tree_view = (GtkTreeView *)data;
8622   GtkRBTree *tree;
8623   GtkRBNode *node;
8624   GList *list;
8625   gint selection_changed = FALSE;
8626
8627   g_return_if_fail (path != NULL);
8628
8629   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8630
8631   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8632     return;
8633
8634   if (tree == NULL)
8635     return;
8636
8637   /* check if the selection has been changed */
8638   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8639                         check_selection_helper, &selection_changed);
8640
8641   for (list = tree_view->priv->columns; list; list = list->next)
8642     if (((GtkTreeViewColumn *)list->data)->visible &&
8643         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8644       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8645
8646   /* Ensure we don't have a dangling pointer to a dead node */
8647   ensure_unprelighted (tree_view);
8648
8649   /* Cancel editting if we've started */
8650   gtk_tree_view_stop_editing (tree_view, TRUE);
8651
8652   /* If we have a node expanded/collapsed timeout, remove it */
8653   remove_expand_collapse_timeout (tree_view);
8654
8655   if (tree_view->priv->destroy_count_func)
8656     {
8657       gint child_count = 0;
8658       if (node->children)
8659         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8660       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8661     }
8662
8663   if (tree->root->count == 1)
8664     {
8665       if (tree_view->priv->tree == tree)
8666         tree_view->priv->tree = NULL;
8667
8668       _gtk_rbtree_remove (tree);
8669     }
8670   else
8671     {
8672       _gtk_rbtree_remove_node (tree, node);
8673     }
8674
8675   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8676     {
8677       gtk_tree_row_reference_free (tree_view->priv->top_row);
8678       tree_view->priv->top_row = NULL;
8679     }
8680
8681   install_scroll_sync_handler (tree_view);
8682
8683   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8684
8685   if (selection_changed)
8686     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8687 }
8688
8689 static void
8690 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8691                               GtkTreePath  *parent,
8692                               GtkTreeIter  *iter,
8693                               gint         *new_order,
8694                               gpointer      data)
8695 {
8696   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8697   GtkRBTree *tree;
8698   GtkRBNode *node;
8699   gint len;
8700
8701   len = gtk_tree_model_iter_n_children (model, iter);
8702
8703   if (len < 2)
8704     return;
8705
8706   gtk_tree_row_reference_reordered (G_OBJECT (data),
8707                                     parent,
8708                                     iter,
8709                                     new_order);
8710
8711   if (_gtk_tree_view_find_node (tree_view,
8712                                 parent,
8713                                 &tree,
8714                                 &node))
8715     return;
8716
8717   /* We need to special case the parent path */
8718   if (tree == NULL)
8719     tree = tree_view->priv->tree;
8720   else
8721     tree = node->children;
8722
8723   if (tree == NULL)
8724     return;
8725
8726   if (tree_view->priv->edited_column)
8727     gtk_tree_view_stop_editing (tree_view, TRUE);
8728
8729   /* we need to be unprelighted */
8730   ensure_unprelighted (tree_view);
8731
8732   /* clear the timeout */
8733   cancel_arrow_animation (tree_view);
8734   
8735   _gtk_rbtree_reorder (tree, new_order, len);
8736
8737   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8738
8739   gtk_tree_view_dy_to_top_row (tree_view);
8740 }
8741
8742
8743 /* Internal tree functions
8744  */
8745
8746
8747 static void
8748 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8749                                      GtkRBTree         *tree,
8750                                      GtkTreeViewColumn *column,
8751                                      gint              *x1,
8752                                      gint              *x2)
8753 {
8754   GtkTreeViewColumn *tmp_column = NULL;
8755   gint total_width;
8756   GList *list;
8757   gboolean rtl;
8758
8759   if (x1)
8760     *x1 = 0;
8761
8762   if (x2)
8763     *x2 = 0;
8764
8765   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8766
8767   total_width = 0;
8768   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8769        list;
8770        list = (rtl ? list->prev : list->next))
8771     {
8772       tmp_column = list->data;
8773
8774       if (tmp_column == column)
8775         break;
8776
8777       if (tmp_column->visible)
8778         total_width += tmp_column->width;
8779     }
8780
8781   if (tmp_column != column)
8782     {
8783       g_warning (G_STRLOC": passed-in column isn't in the tree");
8784       return;
8785     }
8786
8787   if (x1)
8788     *x1 = total_width;
8789
8790   if (x2)
8791     {
8792       if (column->visible)
8793         *x2 = total_width + column->width;
8794       else
8795         *x2 = total_width; /* width of 0 */
8796     }
8797 }
8798 static void
8799 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8800                                 GtkRBTree   *tree,
8801                                 gint        *x1,
8802                                 gint        *x2)
8803 {
8804   gint x_offset = 0;
8805   GList *list;
8806   GtkTreeViewColumn *tmp_column = NULL;
8807   gint total_width;
8808   gboolean indent_expanders;
8809   gboolean rtl;
8810
8811   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8812
8813   total_width = 0;
8814   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8815        list;
8816        list = (rtl ? list->prev : list->next))
8817     {
8818       tmp_column = list->data;
8819
8820       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8821         {
8822           if (rtl)
8823             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8824           else
8825             x_offset = total_width;
8826           break;
8827         }
8828
8829       if (tmp_column->visible)
8830         total_width += tmp_column->width;
8831     }
8832
8833   gtk_widget_style_get (GTK_WIDGET (tree_view),
8834                         "indent-expanders", &indent_expanders,
8835                         NULL);
8836
8837   if (indent_expanders)
8838     {
8839       if (rtl)
8840         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8841       else
8842         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8843     }
8844
8845   *x1 = x_offset;
8846   
8847   if (tmp_column && tmp_column->visible)
8848     /* +1 because x2 isn't included in the range. */
8849     *x2 = *x1 + tree_view->priv->expander_size + 1;
8850   else
8851     *x2 = *x1;
8852 }
8853
8854 static void
8855 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8856                           GtkRBTree   *tree,
8857                           GtkTreeIter *iter,
8858                           gint         depth,
8859                           gboolean     recurse)
8860 {
8861   GtkRBNode *temp = NULL;
8862   GtkTreePath *path = NULL;
8863   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8864
8865   do
8866     {
8867       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8868       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8869
8870       if (tree_view->priv->fixed_height > 0)
8871         {
8872           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8873             {
8874               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8875               _gtk_rbtree_node_mark_valid (tree, temp);
8876             }
8877         }
8878
8879       if (is_list)
8880         continue;
8881
8882       if (recurse)
8883         {
8884           GtkTreeIter child;
8885
8886           if (!path)
8887             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8888           else
8889             gtk_tree_path_next (path);
8890
8891           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8892             {
8893               gboolean expand;
8894
8895               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8896
8897               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8898                   && !expand)
8899                 {
8900                   temp->children = _gtk_rbtree_new ();
8901                   temp->children->parent_tree = tree;
8902                   temp->children->parent_node = temp;
8903                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8904                 }
8905             }
8906         }
8907
8908       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8909         {
8910           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8911             temp->flags ^= GTK_RBNODE_IS_PARENT;
8912         }
8913     }
8914   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8915
8916   if (path)
8917     gtk_tree_path_free (path);
8918 }
8919
8920 /* Make sure the node is visible vertically */
8921 static void
8922 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8923                                   GtkRBTree   *tree,
8924                                   GtkRBNode   *node)
8925 {
8926   gint node_dy, height;
8927   GtkTreePath *path = NULL;
8928
8929   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8930     return;
8931
8932   /* just return if the node is visible, avoiding a costly expose */
8933   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8934   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8935   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8936       && node_dy >= tree_view->priv->vadjustment->value
8937       && node_dy + height <= (tree_view->priv->vadjustment->value
8938                               + tree_view->priv->vadjustment->page_size))
8939     return;
8940
8941   path = _gtk_tree_view_find_path (tree_view, tree, node);
8942   if (path)
8943     {
8944       /* We process updates because we want to clear old selected items when we scroll.
8945        * if this is removed, we get a "selection streak" at the bottom. */
8946       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8947       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8948       gtk_tree_path_free (path);
8949     }
8950 }
8951
8952 static void
8953 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8954                                     GtkTreeViewColumn *column,
8955                                     gboolean           focus_to_cell)
8956 {
8957   GtkAllocation allocation;
8958   gint x, width;
8959
8960   if (column == NULL)
8961     return;
8962
8963   gtk_widget_get_allocation (column->button, &allocation);
8964   x = allocation.x;
8965   width = allocation.width;
8966
8967   if (width > tree_view->priv->hadjustment->page_size)
8968     {
8969       /* The column is larger than the horizontal page size.  If the
8970        * column has cells which can be focussed individually, then we make
8971        * sure the cell which gets focus is fully visible (if even the
8972        * focus cell is bigger than the page size, we make sure the
8973        * left-hand side of the cell is visible).
8974        *
8975        * If the column does not have those so-called special cells, we
8976        * make sure the left-hand side of the column is visible.
8977        */
8978
8979       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8980         {
8981           GtkTreePath *cursor_path;
8982           GdkRectangle background_area, cell_area, focus_area;
8983
8984           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8985
8986           gtk_tree_view_get_cell_area (tree_view,
8987                                        cursor_path, column, &cell_area);
8988           gtk_tree_view_get_background_area (tree_view,
8989                                              cursor_path, column,
8990                                              &background_area);
8991
8992           gtk_tree_path_free (cursor_path);
8993
8994           _gtk_tree_view_column_get_focus_area (column,
8995                                                 &background_area,
8996                                                 &cell_area,
8997                                                 &focus_area);
8998
8999           x = focus_area.x;
9000           width = focus_area.width;
9001
9002           if (width < tree_view->priv->hadjustment->page_size)
9003             {
9004               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9005                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
9006                                           x + width - tree_view->priv->hadjustment->page_size);
9007               else if (tree_view->priv->hadjustment->value > x)
9008                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9009             }
9010         }
9011
9012       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9013     }
9014   else
9015     {
9016       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9017           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9018                                     x + width - tree_view->priv->hadjustment->page_size);
9019       else if (tree_view->priv->hadjustment->value > x)
9020         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9021   }
9022 }
9023
9024 /* This function could be more efficient.  I'll optimize it if profiling seems
9025  * to imply that it is important */
9026 GtkTreePath *
9027 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9028                           GtkRBTree   *tree,
9029                           GtkRBNode   *node)
9030 {
9031   GtkTreePath *path;
9032   GtkRBTree *tmp_tree;
9033   GtkRBNode *tmp_node, *last;
9034   gint count;
9035
9036   path = gtk_tree_path_new ();
9037
9038   g_return_val_if_fail (node != NULL, path);
9039   g_return_val_if_fail (node != tree->nil, path);
9040
9041   count = 1 + node->left->count;
9042
9043   last = node;
9044   tmp_node = node->parent;
9045   tmp_tree = tree;
9046   while (tmp_tree)
9047     {
9048       while (tmp_node != tmp_tree->nil)
9049         {
9050           if (tmp_node->right == last)
9051             count += 1 + tmp_node->left->count;
9052           last = tmp_node;
9053           tmp_node = tmp_node->parent;
9054         }
9055       gtk_tree_path_prepend_index (path, count - 1);
9056       last = tmp_tree->parent_node;
9057       tmp_tree = tmp_tree->parent_tree;
9058       if (last)
9059         {
9060           count = 1 + last->left->count;
9061           tmp_node = last->parent;
9062         }
9063     }
9064   return path;
9065 }
9066
9067 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9068  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9069  * both set to NULL.
9070  */
9071 gboolean
9072 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9073                           GtkTreePath  *path,
9074                           GtkRBTree   **tree,
9075                           GtkRBNode   **node)
9076 {
9077   GtkRBNode *tmpnode = NULL;
9078   GtkRBTree *tmptree = tree_view->priv->tree;
9079   gint *indices = gtk_tree_path_get_indices (path);
9080   gint depth = gtk_tree_path_get_depth (path);
9081   gint i = 0;
9082
9083   *node = NULL;
9084   *tree = NULL;
9085
9086   if (depth == 0 || tmptree == NULL)
9087     return FALSE;
9088   do
9089     {
9090       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9091       ++i;
9092       if (tmpnode == NULL)
9093         {
9094           *tree = NULL;
9095           *node = NULL;
9096           return FALSE;
9097         }
9098       if (i >= depth)
9099         {
9100           *tree = tmptree;
9101           *node = tmpnode;
9102           return FALSE;
9103         }
9104       *tree = tmptree;
9105       *node = tmpnode;
9106       tmptree = tmpnode->children;
9107       if (tmptree == NULL)
9108         return TRUE;
9109     }
9110   while (1);
9111 }
9112
9113 static gboolean
9114 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9115                                   GtkTreeViewColumn *column)
9116 {
9117   GList *list;
9118
9119   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9120     return FALSE;
9121
9122   if (tree_view->priv->expander_column != NULL)
9123     {
9124       if (tree_view->priv->expander_column == column)
9125         return TRUE;
9126       return FALSE;
9127     }
9128   else
9129     {
9130       for (list = tree_view->priv->columns;
9131            list;
9132            list = list->next)
9133         if (((GtkTreeViewColumn *)list->data)->visible)
9134           break;
9135       if (list && list->data == column)
9136         return TRUE;
9137     }
9138   return FALSE;
9139 }
9140
9141 static void
9142 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9143                                 guint           keyval,
9144                                 guint           modmask,
9145                                 gboolean        add_shifted_binding,
9146                                 GtkMovementStep step,
9147                                 gint            count)
9148 {
9149   
9150   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9151                                 "move-cursor", 2,
9152                                 G_TYPE_ENUM, step,
9153                                 G_TYPE_INT, count);
9154
9155   if (add_shifted_binding)
9156     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9157                                   "move-cursor", 2,
9158                                   G_TYPE_ENUM, step,
9159                                   G_TYPE_INT, count);
9160
9161   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9162    return;
9163
9164   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9165                                 "move-cursor", 2,
9166                                 G_TYPE_ENUM, step,
9167                                 G_TYPE_INT, count);
9168
9169   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9170                                 "move-cursor", 2,
9171                                 G_TYPE_ENUM, step,
9172                                 G_TYPE_INT, count);
9173 }
9174
9175 static gint
9176 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9177                                  GtkTreeIter  *iter,
9178                                  GtkRBTree    *tree,
9179                                  GtkRBNode    *node)
9180 {
9181   gint retval = FALSE;
9182   do
9183     {
9184       g_return_val_if_fail (node != NULL, FALSE);
9185
9186       if (node->children)
9187         {
9188           GtkTreeIter child;
9189           GtkRBTree *new_tree;
9190           GtkRBNode *new_node;
9191
9192           new_tree = node->children;
9193           new_node = new_tree->root;
9194
9195           while (new_node && new_node->left != new_tree->nil)
9196             new_node = new_node->left;
9197
9198           if (!gtk_tree_model_iter_children (model, &child, iter))
9199             return FALSE;
9200
9201           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9202         }
9203
9204       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9205         retval = TRUE;
9206       gtk_tree_model_unref_node (model, iter);
9207       node = _gtk_rbtree_next (tree, node);
9208     }
9209   while (gtk_tree_model_iter_next (model, iter));
9210
9211   return retval;
9212 }
9213
9214 static gint
9215 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9216                                               GtkRBTree   *tree)
9217 {
9218   GtkTreeIter iter;
9219   GtkTreePath *path;
9220   GtkRBNode *node;
9221   gint retval;
9222
9223   if (!tree)
9224     return FALSE;
9225
9226   node = tree->root;
9227   while (node && node->left != tree->nil)
9228     node = node->left;
9229
9230   g_return_val_if_fail (node != NULL, FALSE);
9231   path = _gtk_tree_view_find_path (tree_view, tree, node);
9232   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9233                            &iter, path);
9234   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9235   gtk_tree_path_free (path);
9236
9237   return retval;
9238 }
9239
9240 static void
9241 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9242                                     GtkTreeViewColumn *column)
9243 {
9244   GtkTreeViewColumn *left_column;
9245   GtkTreeViewColumn *cur_column = NULL;
9246   GtkTreeViewColumnReorder *reorder;
9247   gboolean rtl;
9248   GList *tmp_list;
9249   gint left;
9250
9251   /* We want to precalculate the motion list such that we know what column slots
9252    * are available.
9253    */
9254   left_column = NULL;
9255   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9256
9257   /* First, identify all possible drop spots */
9258   if (rtl)
9259     tmp_list = g_list_last (tree_view->priv->columns);
9260   else
9261     tmp_list = g_list_first (tree_view->priv->columns);
9262
9263   while (tmp_list)
9264     {
9265       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9266       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9267
9268       if (cur_column->visible == FALSE)
9269         continue;
9270
9271       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9272       if (left_column != column && cur_column != column &&
9273           tree_view->priv->column_drop_func &&
9274           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9275         {
9276           left_column = cur_column;
9277           continue;
9278         }
9279       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9280       reorder->left_column = left_column;
9281       left_column = reorder->right_column = cur_column;
9282
9283       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9284     }
9285
9286   /* Add the last one */
9287   if (tree_view->priv->column_drop_func == NULL ||
9288       ((left_column != column) &&
9289        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9290     {
9291       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9292       reorder->left_column = left_column;
9293       reorder->right_column = NULL;
9294       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9295     }
9296
9297   /* We quickly check to see if it even makes sense to reorder columns. */
9298   /* If there is nothing that can be moved, then we return */
9299
9300   if (tree_view->priv->column_drag_info == NULL)
9301     return;
9302
9303   /* We know there are always 2 slots possbile, as you can always return column. */
9304   /* If that's all there is, return */
9305   if (tree_view->priv->column_drag_info->next == NULL || 
9306       (tree_view->priv->column_drag_info->next->next == NULL &&
9307        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9308        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9309     {
9310       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9311         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9312       g_list_free (tree_view->priv->column_drag_info);
9313       tree_view->priv->column_drag_info = NULL;
9314       return;
9315     }
9316   /* We fill in the ranges for the columns, now that we've isolated them */
9317   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9318
9319   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9320     {
9321       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9322
9323       reorder->left_align = left;
9324       if (tmp_list->next != NULL)
9325         {
9326           GtkAllocation right_allocation, left_allocation;
9327
9328           g_assert (tmp_list->next->data);
9329
9330           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9331           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9332           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9333         }
9334       else
9335         {
9336           gint width;
9337
9338           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9339           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9340         }
9341     }
9342 }
9343
9344 void
9345 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9346                                   GtkTreeViewColumn *column,
9347                                   GdkDevice         *device)
9348 {
9349   GdkEvent *send_event;
9350   GtkAllocation allocation;
9351   GtkAllocation button_allocation;
9352   gint x, y, width, height;
9353   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9354   GdkDisplay *display = gdk_screen_get_display (screen);
9355
9356   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9357   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9358
9359   gtk_tree_view_set_column_drag_info (tree_view, column);
9360
9361   if (tree_view->priv->column_drag_info == NULL)
9362     return;
9363
9364   if (tree_view->priv->drag_window == NULL)
9365     {
9366       GdkWindowAttr attributes;
9367       guint attributes_mask;
9368
9369       gtk_widget_get_allocation (column->button, &button_allocation);
9370
9371       attributes.window_type = GDK_WINDOW_CHILD;
9372       attributes.wclass = GDK_INPUT_OUTPUT;
9373       attributes.x = button_allocation.x;
9374       attributes.y = 0;
9375       attributes.width = button_allocation.width;
9376       attributes.height = button_allocation.height;
9377       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9378       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9379       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9380       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9381
9382       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9383                                                      &attributes,
9384                                                      attributes_mask);
9385       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9386     }
9387
9388   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9389   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9390
9391   gtk_grab_remove (column->button);
9392
9393   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9394   send_event->crossing.send_event = TRUE;
9395   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9396   send_event->crossing.subwindow = NULL;
9397   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9398   send_event->crossing.time = GDK_CURRENT_TIME;
9399   gdk_event_set_device (send_event, device);
9400
9401   gtk_propagate_event (column->button, send_event);
9402   gdk_event_free (send_event);
9403
9404   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9405   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9406   send_event->button.send_event = TRUE;
9407   send_event->button.time = GDK_CURRENT_TIME;
9408   send_event->button.x = -1;
9409   send_event->button.y = -1;
9410   send_event->button.axes = NULL;
9411   send_event->button.state = 0;
9412   send_event->button.button = 1;
9413   send_event->button.x_root = 0;
9414   send_event->button.y_root = 0;
9415   gdk_event_set_device (send_event, device);
9416
9417   gtk_propagate_event (column->button, send_event);
9418   gdk_event_free (send_event);
9419
9420   /* Kids, don't try this at home */
9421   g_object_ref (column->button);
9422   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9423   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9424   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9425   g_object_unref (column->button);
9426
9427   gtk_widget_get_allocation (column->button, &button_allocation);
9428   tree_view->priv->drag_column_x = button_allocation.x;
9429   allocation = button_allocation;
9430   allocation.x = 0;
9431   gtk_widget_size_allocate (column->button, &allocation);
9432   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9433
9434   tree_view->priv->drag_column = column;
9435   gdk_window_show (tree_view->priv->drag_window);
9436
9437   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9438   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9439
9440   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9441   while (gtk_events_pending ())
9442     gtk_main_iteration ();
9443
9444   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9445   gdk_pointer_grab (tree_view->priv->drag_window,
9446                     FALSE,
9447                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9448                     NULL, NULL, GDK_CURRENT_TIME);
9449   gdk_keyboard_grab (tree_view->priv->drag_window,
9450                      FALSE,
9451                      GDK_CURRENT_TIME);
9452 }
9453
9454 static void
9455 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9456                                 GtkRBTree          *tree,
9457                                 GtkRBNode          *node,
9458                                 const GdkRectangle *clip_rect)
9459 {
9460   GtkAllocation allocation;
9461   GdkRectangle rect;
9462
9463   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9464     return;
9465
9466   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9467   rect.x = 0;
9468   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9469
9470   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9471   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9472
9473   if (clip_rect)
9474     {
9475       GdkRectangle new_rect;
9476
9477       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9478
9479       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9480     }
9481   else
9482     {
9483       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9484     }
9485 }
9486
9487 void
9488 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9489                                 GtkRBTree          *tree,
9490                                 GtkRBNode          *node,
9491                                 const GdkRectangle *clip_rect)
9492 {
9493   GtkAllocation allocation;
9494   GdkRectangle rect;
9495
9496   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9497     return;
9498
9499   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9500   rect.x = 0;
9501   rect.width = MAX (tree_view->priv->width, allocation.width);
9502
9503   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9504   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9505
9506   if (clip_rect)
9507     {
9508       GdkRectangle new_rect;
9509
9510       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9511
9512       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9513     }
9514   else
9515     {
9516       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9517     }
9518 }
9519
9520 static void
9521 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9522                                GtkTreePath        *path,
9523                                const GdkRectangle *clip_rect)
9524 {
9525   GtkRBTree *tree = NULL;
9526   GtkRBNode *node = NULL;
9527
9528   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9529
9530   if (tree)
9531     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9532 }
9533
9534 /* x and y are the mouse position
9535  */
9536 static void
9537 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9538                           GtkRBTree   *tree,
9539                           GtkRBNode   *node,
9540                           /* in bin_window coordinates */
9541                           gint         x,
9542                           gint         y)
9543 {
9544   GdkRectangle area;
9545   GtkStateType state;
9546   GtkWidget *widget;
9547   gint x_offset = 0;
9548   gint x2;
9549   gint vertical_separator;
9550   gint expander_size;
9551   GtkExpanderStyle expander_style;
9552
9553   widget = GTK_WIDGET (tree_view);
9554
9555   gtk_widget_style_get (widget,
9556                         "vertical-separator", &vertical_separator,
9557                         NULL);
9558   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9559
9560   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9561     return;
9562
9563   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9564
9565   area.x = x_offset;
9566   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9567   area.width = expander_size + 2;
9568   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9569
9570   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9571     {
9572       state = GTK_STATE_INSENSITIVE;
9573     }
9574   else if (node == tree_view->priv->button_pressed_node)
9575     {
9576       if (x >= area.x && x <= (area.x + area.width) &&
9577           y >= area.y && y <= (area.y + area.height))
9578         state = GTK_STATE_ACTIVE;
9579       else
9580         state = GTK_STATE_NORMAL;
9581     }
9582   else
9583     {
9584       if (node == tree_view->priv->prelight_node &&
9585           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9586         state = GTK_STATE_PRELIGHT;
9587       else
9588         state = GTK_STATE_NORMAL;
9589     }
9590
9591   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9592     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9593   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9594     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9595   else if (node->children != NULL)
9596     expander_style = GTK_EXPANDER_EXPANDED;
9597   else
9598     expander_style = GTK_EXPANDER_COLLAPSED;
9599
9600   gtk_paint_expander (gtk_widget_get_style (widget),
9601                       tree_view->priv->bin_window,
9602                       state,
9603                       &area,
9604                       widget,
9605                       "treeview",
9606                       area.x + area.width / 2,
9607                       area.y + area.height / 2,
9608                       expander_style);
9609 }
9610
9611 static void
9612 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9613
9614 {
9615   GtkTreePath *cursor_path;
9616
9617   if ((tree_view->priv->tree == NULL) ||
9618       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9619     return;
9620
9621   cursor_path = NULL;
9622   if (tree_view->priv->cursor)
9623     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9624
9625   if (cursor_path == NULL)
9626     {
9627       /* Consult the selection before defaulting to the
9628        * first focusable element
9629        */
9630       GList *selected_rows;
9631       GtkTreeModel *model;
9632       GtkTreeSelection *selection;
9633
9634       selection = gtk_tree_view_get_selection (tree_view);
9635       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9636
9637       if (selected_rows)
9638         {
9639           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9640           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9641           g_list_free (selected_rows);
9642         }
9643       else
9644         {
9645           cursor_path = gtk_tree_path_new_first ();
9646           search_first_focusable_path (tree_view, &cursor_path,
9647                                        TRUE, NULL, NULL);
9648         }
9649
9650       gtk_tree_row_reference_free (tree_view->priv->cursor);
9651       tree_view->priv->cursor = NULL;
9652
9653       if (cursor_path)
9654         {
9655           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9656             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9657           else
9658             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9659         }
9660     }
9661
9662   if (cursor_path)
9663     {
9664       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9665
9666       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9667       gtk_tree_path_free (cursor_path);
9668
9669       if (tree_view->priv->focus_column == NULL)
9670         {
9671           GList *list;
9672           for (list = tree_view->priv->columns; list; list = list->next)
9673             {
9674               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9675                 {
9676                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9677                   break;
9678                 }
9679             }
9680         }
9681     }
9682 }
9683
9684 static void
9685 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9686                                    gint         count)
9687 {
9688   gint selection_count;
9689   GtkRBTree *cursor_tree = NULL;
9690   GtkRBNode *cursor_node = NULL;
9691   GtkRBTree *new_cursor_tree = NULL;
9692   GtkRBNode *new_cursor_node = NULL;
9693   GtkTreePath *cursor_path = NULL;
9694   gboolean grab_focus = TRUE;
9695   gboolean selectable;
9696
9697   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9698     return;
9699
9700   cursor_path = NULL;
9701   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9702     /* FIXME: we lost the cursor; should we get the first? */
9703     return;
9704
9705   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9706   _gtk_tree_view_find_node (tree_view, cursor_path,
9707                             &cursor_tree, &cursor_node);
9708
9709   if (cursor_tree == NULL)
9710     /* FIXME: we lost the cursor; should we get the first? */
9711     return;
9712
9713   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9714   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9715                                                       cursor_node,
9716                                                       cursor_path);
9717
9718   if (selection_count == 0
9719       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9720       && !tree_view->priv->ctrl_pressed
9721       && selectable)
9722     {
9723       /* Don't move the cursor, but just select the current node */
9724       new_cursor_tree = cursor_tree;
9725       new_cursor_node = cursor_node;
9726     }
9727   else
9728     {
9729       if (count == -1)
9730         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9731                                &new_cursor_tree, &new_cursor_node);
9732       else
9733         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9734                                &new_cursor_tree, &new_cursor_node);
9735     }
9736
9737   gtk_tree_path_free (cursor_path);
9738
9739   if (new_cursor_node)
9740     {
9741       cursor_path = _gtk_tree_view_find_path (tree_view,
9742                                               new_cursor_tree, new_cursor_node);
9743
9744       search_first_focusable_path (tree_view, &cursor_path,
9745                                    (count != -1),
9746                                    &new_cursor_tree,
9747                                    &new_cursor_node);
9748
9749       if (cursor_path)
9750         gtk_tree_path_free (cursor_path);
9751     }
9752
9753   /*
9754    * If the list has only one item and multi-selection is set then select
9755    * the row (if not yet selected).
9756    */
9757   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9758       new_cursor_node == NULL)
9759     {
9760       if (count == -1)
9761         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9762                                &new_cursor_tree, &new_cursor_node);
9763       else
9764         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9765                                &new_cursor_tree, &new_cursor_node);
9766
9767       if (new_cursor_node == NULL
9768           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9769         {
9770           new_cursor_node = cursor_node;
9771           new_cursor_tree = cursor_tree;
9772         }
9773       else
9774         {
9775           new_cursor_node = NULL;
9776         }
9777     }
9778
9779   if (new_cursor_node)
9780     {
9781       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9782       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9783       gtk_tree_path_free (cursor_path);
9784     }
9785   else
9786     {
9787       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9788
9789       if (!tree_view->priv->shift_pressed)
9790         {
9791           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9792                                           count < 0 ?
9793                                           GTK_DIR_UP : GTK_DIR_DOWN))
9794             {
9795               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9796
9797               if (toplevel)
9798                 gtk_widget_child_focus (toplevel,
9799                                         count < 0 ?
9800                                         GTK_DIR_TAB_BACKWARD :
9801                                         GTK_DIR_TAB_FORWARD);
9802
9803               grab_focus = FALSE;
9804             }
9805         }
9806       else
9807         {
9808           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9809         }
9810     }
9811
9812   if (grab_focus)
9813     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9814 }
9815
9816 static void
9817 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9818                                         gint         count)
9819 {
9820   GtkRBTree *cursor_tree = NULL;
9821   GtkRBNode *cursor_node = NULL;
9822   GtkTreePath *old_cursor_path = NULL;
9823   GtkTreePath *cursor_path = NULL;
9824   GtkRBTree *start_cursor_tree = NULL;
9825   GtkRBNode *start_cursor_node = NULL;
9826   gint y;
9827   gint window_y;
9828   gint vertical_separator;
9829
9830   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9831     return;
9832
9833   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9834     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9835   else
9836     /* This is sorta weird.  Focus in should give us a cursor */
9837     return;
9838
9839   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9840   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9841                             &cursor_tree, &cursor_node);
9842
9843   if (cursor_tree == NULL)
9844     {
9845       /* FIXME: we lost the cursor.  Should we try to get one? */
9846       gtk_tree_path_free (old_cursor_path);
9847       return;
9848     }
9849   g_return_if_fail (cursor_node != NULL);
9850
9851   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9852   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9853   y += tree_view->priv->cursor_offset;
9854   y += count * (int)tree_view->priv->vadjustment->page_increment;
9855   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9856
9857   if (y >= tree_view->priv->height)
9858     y = tree_view->priv->height - 1;
9859
9860   tree_view->priv->cursor_offset =
9861     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9862                              &cursor_tree, &cursor_node);
9863
9864   if (cursor_tree == NULL)
9865     {
9866       /* FIXME: we lost the cursor.  Should we try to get one? */
9867       gtk_tree_path_free (old_cursor_path);
9868       return;
9869     }
9870
9871   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9872     {
9873       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9874                              &cursor_tree, &cursor_node);
9875       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9876     }
9877
9878   y -= tree_view->priv->cursor_offset;
9879   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9880
9881   start_cursor_tree = cursor_tree;
9882   start_cursor_node = cursor_node;
9883
9884   if (! search_first_focusable_path (tree_view, &cursor_path,
9885                                      (count != -1),
9886                                      &cursor_tree, &cursor_node))
9887     {
9888       /* It looks like we reached the end of the view without finding
9889        * a focusable row.  We will step backwards to find the last
9890        * focusable row.
9891        */
9892       cursor_tree = start_cursor_tree;
9893       cursor_node = start_cursor_node;
9894       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9895
9896       search_first_focusable_path (tree_view, &cursor_path,
9897                                    (count == -1),
9898                                    &cursor_tree, &cursor_node);
9899     }
9900
9901   if (!cursor_path)
9902     goto cleanup;
9903
9904   /* update y */
9905   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9906
9907   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9908
9909   y -= window_y;
9910   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9911   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9912   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9913
9914   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9915     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9916
9917   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9918
9919 cleanup:
9920   gtk_tree_path_free (old_cursor_path);
9921   gtk_tree_path_free (cursor_path);
9922 }
9923
9924 static void
9925 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9926                                       gint         count)
9927 {
9928   GtkRBTree *cursor_tree = NULL;
9929   GtkRBNode *cursor_node = NULL;
9930   GtkTreePath *cursor_path = NULL;
9931   GtkTreeViewColumn *column;
9932   GtkTreeIter iter;
9933   GList *list;
9934   gboolean found_column = FALSE;
9935   gboolean rtl;
9936
9937   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9938
9939   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9940     return;
9941
9942   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9943     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9944   else
9945     return;
9946
9947   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9948   if (cursor_tree == NULL)
9949     return;
9950   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9951     {
9952       gtk_tree_path_free (cursor_path);
9953       return;
9954     }
9955   gtk_tree_path_free (cursor_path);
9956
9957   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9958   if (tree_view->priv->focus_column)
9959     {
9960       for (; list; list = (rtl ? list->prev : list->next))
9961         {
9962           if (list->data == tree_view->priv->focus_column)
9963             break;
9964         }
9965     }
9966
9967   while (list)
9968     {
9969       gboolean left, right;
9970
9971       column = list->data;
9972       if (column->visible == FALSE)
9973         goto loop_end;
9974
9975       gtk_tree_view_column_cell_set_cell_data (column,
9976                                                tree_view->priv->model,
9977                                                &iter,
9978                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9979                                                cursor_node->children?TRUE:FALSE);
9980
9981       if (rtl)
9982         {
9983           right = list->prev ? TRUE : FALSE;
9984           left = list->next ? TRUE : FALSE;
9985         }
9986       else
9987         {
9988           left = list->prev ? TRUE : FALSE;
9989           right = list->next ? TRUE : FALSE;
9990         }
9991
9992       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9993         {
9994           tree_view->priv->focus_column = column;
9995           found_column = TRUE;
9996           break;
9997         }
9998     loop_end:
9999       if (count == 1)
10000         list = rtl ? list->prev : list->next;
10001       else
10002         list = rtl ? list->next : list->prev;
10003     }
10004
10005   if (found_column)
10006     {
10007       if (!gtk_tree_view_has_special_cell (tree_view))
10008         _gtk_tree_view_queue_draw_node (tree_view,
10009                                         cursor_tree,
10010                                         cursor_node,
10011                                         NULL);
10012       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10013       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10014     }
10015   else
10016     {
10017       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10018     }
10019
10020   gtk_tree_view_clamp_column_visible (tree_view,
10021                                       tree_view->priv->focus_column, TRUE);
10022 }
10023
10024 static void
10025 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10026                                      gint         count)
10027 {
10028   GtkRBTree *cursor_tree;
10029   GtkRBNode *cursor_node;
10030   GtkTreePath *path;
10031   GtkTreePath *old_path;
10032
10033   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10034     return;
10035
10036   g_return_if_fail (tree_view->priv->tree != NULL);
10037
10038   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10039
10040   cursor_tree = tree_view->priv->tree;
10041   cursor_node = cursor_tree->root;
10042
10043   if (count == -1)
10044     {
10045       while (cursor_node && cursor_node->left != cursor_tree->nil)
10046         cursor_node = cursor_node->left;
10047
10048       /* Now go forward to find the first focusable row. */
10049       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10050       search_first_focusable_path (tree_view, &path,
10051                                    TRUE, &cursor_tree, &cursor_node);
10052     }
10053   else
10054     {
10055       do
10056         {
10057           while (cursor_node && cursor_node->right != cursor_tree->nil)
10058             cursor_node = cursor_node->right;
10059           if (cursor_node->children == NULL)
10060             break;
10061
10062           cursor_tree = cursor_node->children;
10063           cursor_node = cursor_tree->root;
10064         }
10065       while (1);
10066
10067       /* Now go backwards to find last focusable row. */
10068       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10069       search_first_focusable_path (tree_view, &path,
10070                                    FALSE, &cursor_tree, &cursor_node);
10071     }
10072
10073   if (!path)
10074     goto cleanup;
10075
10076   if (gtk_tree_path_compare (old_path, path))
10077     {
10078       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10079       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10080     }
10081   else
10082     {
10083       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10084     }
10085
10086 cleanup:
10087   gtk_tree_path_free (old_path);
10088   gtk_tree_path_free (path);
10089 }
10090
10091 static gboolean
10092 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10093 {
10094   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10095     return FALSE;
10096
10097   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10098     return FALSE;
10099
10100   gtk_tree_selection_select_all (tree_view->priv->selection);
10101
10102   return TRUE;
10103 }
10104
10105 static gboolean
10106 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10107 {
10108   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10109     return FALSE;
10110
10111   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10112     return FALSE;
10113
10114   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10115
10116   return TRUE;
10117 }
10118
10119 static gboolean
10120 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10121                                       gboolean     start_editing)
10122 {
10123   GtkRBTree *new_tree = NULL;
10124   GtkRBNode *new_node = NULL;
10125   GtkRBTree *cursor_tree = NULL;
10126   GtkRBNode *cursor_node = NULL;
10127   GtkTreePath *cursor_path = NULL;
10128   GtkTreeSelectMode mode = 0;
10129
10130   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10131     return FALSE;
10132
10133   if (tree_view->priv->cursor)
10134     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10135
10136   if (cursor_path == NULL)
10137     return FALSE;
10138
10139   _gtk_tree_view_find_node (tree_view, cursor_path,
10140                             &cursor_tree, &cursor_node);
10141
10142   if (cursor_tree == NULL)
10143     {
10144       gtk_tree_path_free (cursor_path);
10145       return FALSE;
10146     }
10147
10148   if (!tree_view->priv->shift_pressed && start_editing &&
10149       tree_view->priv->focus_column)
10150     {
10151       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10152         {
10153           gtk_tree_path_free (cursor_path);
10154           return TRUE;
10155         }
10156     }
10157
10158   if (tree_view->priv->ctrl_pressed)
10159     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10160   if (tree_view->priv->shift_pressed)
10161     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10162
10163   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10164                                             cursor_node,
10165                                             cursor_tree,
10166                                             cursor_path,
10167                                             mode,
10168                                             FALSE);
10169
10170   /* We bail out if the original (tree, node) don't exist anymore after
10171    * handling the selection-changed callback.  We do return TRUE because
10172    * the key press has been handled at this point.
10173    */
10174   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10175
10176   if (cursor_tree != new_tree || cursor_node != new_node)
10177     return FALSE;
10178
10179   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10180
10181   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10182   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10183
10184   if (!tree_view->priv->shift_pressed)
10185     gtk_tree_view_row_activated (tree_view, cursor_path,
10186                                  tree_view->priv->focus_column);
10187     
10188   gtk_tree_path_free (cursor_path);
10189
10190   return TRUE;
10191 }
10192
10193 static gboolean
10194 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10195 {
10196   GtkRBTree *new_tree = NULL;
10197   GtkRBNode *new_node = NULL;
10198   GtkRBTree *cursor_tree = NULL;
10199   GtkRBNode *cursor_node = NULL;
10200   GtkTreePath *cursor_path = NULL;
10201
10202   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10203     return FALSE;
10204
10205   cursor_path = NULL;
10206   if (tree_view->priv->cursor)
10207     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10208
10209   if (cursor_path == NULL)
10210     return FALSE;
10211
10212   _gtk_tree_view_find_node (tree_view, cursor_path,
10213                             &cursor_tree, &cursor_node);
10214   if (cursor_tree == NULL)
10215     {
10216       gtk_tree_path_free (cursor_path);
10217       return FALSE;
10218     }
10219
10220   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10221                                             cursor_node,
10222                                             cursor_tree,
10223                                             cursor_path,
10224                                             GTK_TREE_SELECT_MODE_TOGGLE,
10225                                             FALSE);
10226
10227   /* We bail out if the original (tree, node) don't exist anymore after
10228    * handling the selection-changed callback.  We do return TRUE because
10229    * the key press has been handled at this point.
10230    */
10231   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10232
10233   if (cursor_tree != new_tree || cursor_node != new_node)
10234     return FALSE;
10235
10236   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10237
10238   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10239   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10240   gtk_tree_path_free (cursor_path);
10241
10242   return TRUE;
10243 }
10244
10245 static gboolean
10246 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10247                                                gboolean     logical,
10248                                                gboolean     expand,
10249                                                gboolean     open_all)
10250 {
10251   GtkTreePath *cursor_path = NULL;
10252   GtkRBTree *tree;
10253   GtkRBNode *node;
10254
10255   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10256     return FALSE;
10257
10258   cursor_path = NULL;
10259   if (tree_view->priv->cursor)
10260     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10261
10262   if (cursor_path == NULL)
10263     return FALSE;
10264
10265   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10266     return FALSE;
10267
10268   /* Don't handle the event if we aren't an expander */
10269   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10270     return FALSE;
10271
10272   if (!logical
10273       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10274     expand = !expand;
10275
10276   if (expand)
10277     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10278   else
10279     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10280
10281   gtk_tree_path_free (cursor_path);
10282
10283   return TRUE;
10284 }
10285
10286 static gboolean
10287 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10288 {
10289   GtkRBTree *cursor_tree = NULL;
10290   GtkRBNode *cursor_node = NULL;
10291   GtkTreePath *cursor_path = NULL;
10292   GdkModifierType state;
10293
10294   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10295     goto out;
10296
10297   cursor_path = NULL;
10298   if (tree_view->priv->cursor)
10299     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10300
10301   if (cursor_path == NULL)
10302     goto out;
10303
10304   _gtk_tree_view_find_node (tree_view, cursor_path,
10305                             &cursor_tree, &cursor_node);
10306   if (cursor_tree == NULL)
10307     {
10308       gtk_tree_path_free (cursor_path);
10309       goto out;
10310     }
10311
10312   if (cursor_tree->parent_node)
10313     {
10314       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10315       cursor_node = cursor_tree->parent_node;
10316       cursor_tree = cursor_tree->parent_tree;
10317
10318       gtk_tree_path_up (cursor_path);
10319
10320       if (gtk_get_current_event_state (&state))
10321         {
10322           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10323             tree_view->priv->ctrl_pressed = TRUE;
10324         }
10325
10326       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10327       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10328
10329       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10330       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10331       gtk_tree_path_free (cursor_path);
10332
10333       tree_view->priv->ctrl_pressed = FALSE;
10334
10335       return TRUE;
10336     }
10337
10338  out:
10339
10340   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10341   return FALSE;
10342 }
10343
10344 static gboolean
10345 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10346 {
10347   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10348   tree_view->priv->typeselect_flush_timeout = 0;
10349
10350   return FALSE;
10351 }
10352
10353 /* Cut and paste from gtkwindow.c */
10354 static void
10355 send_focus_change (GtkWidget *widget,
10356                    GdkDevice *device,
10357                    gboolean   in)
10358 {
10359   GdkDeviceManager *device_manager;
10360   GList *devices, *d;
10361
10362   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10363   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10364   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10365   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10366
10367   for (d = devices; d; d = d->next)
10368     {
10369       GdkDevice *dev = d->data;
10370       GdkEvent *fevent;
10371       GdkWindow *window;
10372
10373       if (dev->source != GDK_SOURCE_KEYBOARD)
10374         continue;
10375
10376       window = gtk_widget_get_window (widget);
10377
10378       /* Skip non-master keyboards that haven't
10379        * selected for events from this window
10380        */
10381       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10382           !gdk_window_get_device_events (window, dev))
10383         continue;
10384
10385       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10386
10387       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10388       fevent->focus_change.window = g_object_ref (window);
10389       fevent->focus_change.in = in;
10390       gdk_event_set_device (fevent, device);
10391
10392       gtk_widget_send_focus_change (widget, fevent);
10393
10394       gdk_event_free (fevent);
10395     }
10396 }
10397
10398 static void
10399 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10400 {
10401   GtkWidget *frame, *vbox, *toplevel;
10402   GdkScreen *screen;
10403
10404   if (tree_view->priv->search_custom_entry_set)
10405     return;
10406
10407   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10408   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10409
10410    if (tree_view->priv->search_window != NULL)
10411      {
10412        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10413          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10414                                       GTK_WINDOW (tree_view->priv->search_window));
10415        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10416          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10417                                          GTK_WINDOW (tree_view->priv->search_window));
10418
10419        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10420
10421        return;
10422      }
10423    
10424   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10425   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10426
10427   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10428     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10429                                  GTK_WINDOW (tree_view->priv->search_window));
10430
10431   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10432                             GDK_WINDOW_TYPE_HINT_UTILITY);
10433   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10434   g_signal_connect (tree_view->priv->search_window, "delete-event",
10435                     G_CALLBACK (gtk_tree_view_search_delete_event),
10436                     tree_view);
10437   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10438                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10439                     tree_view);
10440   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10441                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10442                     tree_view);
10443   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10444                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10445                     tree_view);
10446
10447   frame = gtk_frame_new (NULL);
10448   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10449   gtk_widget_show (frame);
10450   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10451
10452   vbox = gtk_vbox_new (FALSE, 0);
10453   gtk_widget_show (vbox);
10454   gtk_container_add (GTK_CONTAINER (frame), vbox);
10455   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10456
10457   /* add entry */
10458   tree_view->priv->search_entry = gtk_entry_new ();
10459   gtk_widget_show (tree_view->priv->search_entry);
10460   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10461                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10462                     tree_view);
10463   g_signal_connect (tree_view->priv->search_entry,
10464                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10465                     tree_view);
10466   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10467                     "preedit-changed",
10468                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10469                     tree_view);
10470   gtk_container_add (GTK_CONTAINER (vbox),
10471                      tree_view->priv->search_entry);
10472
10473   gtk_widget_realize (tree_view->priv->search_entry);
10474 }
10475
10476 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10477  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10478  */
10479 static gboolean
10480 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10481                                              GdkDevice   *device,
10482                                              gboolean     keybinding)
10483 {
10484   /* We only start interactive search if we have focus or the columns
10485    * have focus.  If one of our children have focus, we don't want to
10486    * start the search.
10487    */
10488   GList *list;
10489   gboolean found_focus = FALSE;
10490   GtkWidgetClass *entry_parent_class;
10491   
10492   if (!tree_view->priv->enable_search && !keybinding)
10493     return FALSE;
10494
10495   if (tree_view->priv->search_custom_entry_set)
10496     return FALSE;
10497
10498   if (tree_view->priv->search_window != NULL &&
10499       gtk_widget_get_visible (tree_view->priv->search_window))
10500     return TRUE;
10501
10502   for (list = tree_view->priv->columns; list; list = list->next)
10503     {
10504       GtkTreeViewColumn *column;
10505
10506       column = list->data;
10507       if (! column->visible)
10508         continue;
10509
10510       if (gtk_widget_has_focus (column->button))
10511         {
10512           found_focus = TRUE;
10513           break;
10514         }
10515     }
10516   
10517   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10518     found_focus = TRUE;
10519
10520   if (!found_focus)
10521     return FALSE;
10522
10523   if (tree_view->priv->search_column < 0)
10524     return FALSE;
10525
10526   gtk_tree_view_ensure_interactive_directory (tree_view);
10527
10528   if (keybinding)
10529     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10530
10531   /* done, show it */
10532   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10533   gtk_widget_show (tree_view->priv->search_window);
10534   if (tree_view->priv->search_entry_changed_id == 0)
10535     {
10536       tree_view->priv->search_entry_changed_id =
10537         g_signal_connect (tree_view->priv->search_entry, "changed",
10538                           G_CALLBACK (gtk_tree_view_search_init),
10539                           tree_view);
10540     }
10541
10542   tree_view->priv->typeselect_flush_timeout =
10543     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10544                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10545                    tree_view);
10546
10547   /* Grab focus will select all the text.  We don't want that to happen, so we
10548    * call the parent instance and bypass the selection change.  This is probably
10549    * really non-kosher. */
10550   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10551   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10552
10553   /* send focus-in event */
10554   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10555
10556   /* search first matching iter */
10557   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10558
10559   return TRUE;
10560 }
10561
10562 static gboolean
10563 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10564 {
10565   return gtk_tree_view_real_start_interactive_search (tree_view,
10566                                                       gtk_get_current_event_device (),
10567                                                       TRUE);
10568 }
10569
10570 /* this function returns the new width of the column being resized given
10571  * the column and x position of the cursor; the x cursor position is passed
10572  * in as a pointer and automagicly corrected if it's beyond min/max limits
10573  */
10574 static gint
10575 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10576                                 gint       i,
10577                                 gint      *x)
10578 {
10579   GtkAllocation allocation;
10580   GtkTreeViewColumn *column;
10581   GtkRequisition button_req;
10582   gint width;
10583   gboolean rtl;
10584
10585   /* first translate the x position from widget->window
10586    * to clist->clist_window
10587    */
10588   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10589   column = g_list_nth (tree_view->priv->columns, i)->data;
10590   gtk_widget_get_allocation (column->button, &allocation);
10591   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10592
10593   /* Clamp down the value */
10594   if (column->min_width == -1)
10595     {
10596       gtk_size_request_get_size (GTK_SIZE_REQUEST (column->button), &button_req, NULL);
10597       width = MAX (button_req.width, width);
10598     }
10599   else
10600     width = MAX (column->min_width,
10601                  width);
10602   if (column->max_width != -1)
10603     width = MIN (width, column->max_width);
10604
10605   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10606
10607   return width;
10608 }
10609
10610
10611 /* FIXME this adjust_allocation is a big cut-and-paste from
10612  * GtkCList, needs to be some "official" way to do this
10613  * factored out.
10614  */
10615 typedef struct
10616 {
10617   GdkWindow *window;
10618   int dx;
10619   int dy;
10620 } ScrollData;
10621
10622 /* The window to which widget->window is relative */
10623 #define ALLOCATION_WINDOW(widget)               \
10624    (!gtk_widget_get_has_window (widget) ?                   \
10625     gtk_widget_get_window (widget) :                        \
10626     gdk_window_get_parent (gtk_widget_get_window (widget)))
10627
10628 static void
10629 adjust_allocation_recurse (GtkWidget *widget,
10630                            gpointer   data)
10631 {
10632   GtkAllocation allocation;
10633   ScrollData *scroll_data = data;
10634
10635   /* Need to really size allocate instead of just poking
10636    * into widget->allocation if the widget is not realized.
10637    * FIXME someone figure out why this was.
10638    */
10639   gtk_widget_get_allocation (widget, &allocation);
10640   if (!gtk_widget_get_realized (widget))
10641     {
10642       if (gtk_widget_get_visible (widget))
10643         {
10644           GdkRectangle tmp_rectangle = allocation;
10645           tmp_rectangle.x += scroll_data->dx;
10646           tmp_rectangle.y += scroll_data->dy;
10647           
10648           gtk_widget_size_allocate (widget, &tmp_rectangle);
10649         }
10650     }
10651   else
10652     {
10653       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10654         {
10655           allocation.x += scroll_data->dx;
10656           allocation.y += scroll_data->dy;
10657           gtk_widget_set_allocation (widget, &allocation);
10658
10659           if (GTK_IS_CONTAINER (widget))
10660             gtk_container_forall (GTK_CONTAINER (widget),
10661                                   adjust_allocation_recurse,
10662                                   data);
10663         }
10664     }
10665 }
10666
10667 static void
10668 adjust_allocation (GtkWidget *widget,
10669                    int        dx,
10670                    int        dy)
10671 {
10672   ScrollData scroll_data;
10673
10674   if (gtk_widget_get_realized (widget))
10675     scroll_data.window = ALLOCATION_WINDOW (widget);
10676   else
10677     scroll_data.window = NULL;
10678     
10679   scroll_data.dx = dx;
10680   scroll_data.dy = dy;
10681   
10682   adjust_allocation_recurse (widget, &scroll_data);
10683 }
10684
10685 /* Callbacks */
10686 static void
10687 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10688                                   GtkTreeView   *tree_view)
10689 {
10690   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10691     {
10692       gint dy;
10693         
10694       gdk_window_move (tree_view->priv->bin_window,
10695                        - tree_view->priv->hadjustment->value,
10696                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10697       gdk_window_move (tree_view->priv->header_window,
10698                        - tree_view->priv->hadjustment->value,
10699                        0);
10700       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10701       if (dy)
10702         {
10703           update_prelight (tree_view,
10704                            tree_view->priv->event_last_x,
10705                            tree_view->priv->event_last_y - dy);
10706
10707           if (tree_view->priv->edited_column &&
10708               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10709             {
10710               GList *list;
10711               GtkWidget *widget;
10712               GtkTreeViewChild *child = NULL;
10713
10714               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10715               adjust_allocation (widget, 0, dy); 
10716               
10717               for (list = tree_view->priv->children; list; list = list->next)
10718                 {
10719                   child = (GtkTreeViewChild *)list->data;
10720                   if (child->widget == widget)
10721                     {
10722                       child->y += dy;
10723                       break;
10724                     }
10725                 }
10726             }
10727         }
10728       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10729
10730       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10731         {
10732           /* update our dy and top_row */
10733           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10734
10735           if (!tree_view->priv->in_top_row_to_dy)
10736             gtk_tree_view_dy_to_top_row (tree_view);
10737         }
10738
10739       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10740       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
10741     }
10742 }
10743
10744 \f
10745
10746 /* Public methods
10747  */
10748
10749 /**
10750  * gtk_tree_view_new:
10751  *
10752  * Creates a new #GtkTreeView widget.
10753  *
10754  * Return value: A newly created #GtkTreeView widget.
10755  **/
10756 GtkWidget *
10757 gtk_tree_view_new (void)
10758 {
10759   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10760 }
10761
10762 /**
10763  * gtk_tree_view_new_with_model:
10764  * @model: the model.
10765  *
10766  * Creates a new #GtkTreeView widget with the model initialized to @model.
10767  *
10768  * Return value: A newly created #GtkTreeView widget.
10769  **/
10770 GtkWidget *
10771 gtk_tree_view_new_with_model (GtkTreeModel *model)
10772 {
10773   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10774 }
10775
10776 /* Public Accessors
10777  */
10778
10779 /**
10780  * gtk_tree_view_get_model:
10781  * @tree_view: a #GtkTreeView
10782  *
10783  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10784  * model is unset.
10785  *
10786  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10787  **/
10788 GtkTreeModel *
10789 gtk_tree_view_get_model (GtkTreeView *tree_view)
10790 {
10791   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10792
10793   return tree_view->priv->model;
10794 }
10795
10796 /**
10797  * gtk_tree_view_set_model:
10798  * @tree_view: A #GtkTreeNode.
10799  * @model: (allow-none): The model.
10800  *
10801  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10802  * set, it will remove it before setting the new model.  If @model is %NULL,
10803  * then it will unset the old model.
10804  **/
10805 void
10806 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10807                          GtkTreeModel *model)
10808 {
10809   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10810   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10811
10812   if (model == tree_view->priv->model)
10813     return;
10814
10815   if (tree_view->priv->scroll_to_path)
10816     {
10817       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10818       tree_view->priv->scroll_to_path = NULL;
10819     }
10820
10821   if (tree_view->priv->model)
10822     {
10823       GList *tmplist = tree_view->priv->columns;
10824
10825       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10826       gtk_tree_view_stop_editing (tree_view, TRUE);
10827
10828       remove_expand_collapse_timeout (tree_view);
10829
10830       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10831                                             gtk_tree_view_row_changed,
10832                                             tree_view);
10833       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10834                                             gtk_tree_view_row_inserted,
10835                                             tree_view);
10836       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10837                                             gtk_tree_view_row_has_child_toggled,
10838                                             tree_view);
10839       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10840                                             gtk_tree_view_row_deleted,
10841                                             tree_view);
10842       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10843                                             gtk_tree_view_rows_reordered,
10844                                             tree_view);
10845
10846       for (; tmplist; tmplist = tmplist->next)
10847         _gtk_tree_view_column_unset_model (tmplist->data,
10848                                            tree_view->priv->model);
10849
10850       if (tree_view->priv->tree)
10851         gtk_tree_view_free_rbtree (tree_view);
10852
10853       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10854       tree_view->priv->drag_dest_row = NULL;
10855       gtk_tree_row_reference_free (tree_view->priv->cursor);
10856       tree_view->priv->cursor = NULL;
10857       gtk_tree_row_reference_free (tree_view->priv->anchor);
10858       tree_view->priv->anchor = NULL;
10859       gtk_tree_row_reference_free (tree_view->priv->top_row);
10860       tree_view->priv->top_row = NULL;
10861       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10862       tree_view->priv->scroll_to_path = NULL;
10863
10864       tree_view->priv->scroll_to_column = NULL;
10865
10866       g_object_unref (tree_view->priv->model);
10867
10868       tree_view->priv->search_column = -1;
10869       tree_view->priv->fixed_height_check = 0;
10870       tree_view->priv->fixed_height = -1;
10871       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10872       tree_view->priv->last_button_x = -1;
10873       tree_view->priv->last_button_y = -1;
10874     }
10875
10876   tree_view->priv->model = model;
10877
10878   if (tree_view->priv->model)
10879     {
10880       gint i;
10881       GtkTreePath *path;
10882       GtkTreeIter iter;
10883       GtkTreeModelFlags flags;
10884
10885       if (tree_view->priv->search_column == -1)
10886         {
10887           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10888             {
10889               GType type = gtk_tree_model_get_column_type (model, i);
10890
10891               if (g_value_type_transformable (type, G_TYPE_STRING))
10892                 {
10893                   tree_view->priv->search_column = i;
10894                   break;
10895                 }
10896             }
10897         }
10898
10899       g_object_ref (tree_view->priv->model);
10900       g_signal_connect (tree_view->priv->model,
10901                         "row-changed",
10902                         G_CALLBACK (gtk_tree_view_row_changed),
10903                         tree_view);
10904       g_signal_connect (tree_view->priv->model,
10905                         "row-inserted",
10906                         G_CALLBACK (gtk_tree_view_row_inserted),
10907                         tree_view);
10908       g_signal_connect (tree_view->priv->model,
10909                         "row-has-child-toggled",
10910                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10911                         tree_view);
10912       g_signal_connect (tree_view->priv->model,
10913                         "row-deleted",
10914                         G_CALLBACK (gtk_tree_view_row_deleted),
10915                         tree_view);
10916       g_signal_connect (tree_view->priv->model,
10917                         "rows-reordered",
10918                         G_CALLBACK (gtk_tree_view_rows_reordered),
10919                         tree_view);
10920
10921       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10922       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10923         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10924       else
10925         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10926
10927       path = gtk_tree_path_new_first ();
10928       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10929         {
10930           tree_view->priv->tree = _gtk_rbtree_new ();
10931           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10932         }
10933       gtk_tree_path_free (path);
10934
10935       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10936       install_presize_handler (tree_view);
10937     }
10938
10939   g_object_notify (G_OBJECT (tree_view), "model");
10940
10941   if (tree_view->priv->selection)
10942   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10943
10944   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10945     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10946 }
10947
10948 /**
10949  * gtk_tree_view_get_selection:
10950  * @tree_view: A #GtkTreeView.
10951  *
10952  * Gets the #GtkTreeSelection associated with @tree_view.
10953  *
10954  * Return value: (transfer none): A #GtkTreeSelection object.
10955  **/
10956 GtkTreeSelection *
10957 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10958 {
10959   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10960
10961   return tree_view->priv->selection;
10962 }
10963
10964 /**
10965  * gtk_tree_view_get_hadjustment:
10966  * @tree_view: A #GtkTreeView
10967  *
10968  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10969  *
10970  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10971  * used.
10972  **/
10973 GtkAdjustment *
10974 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10975 {
10976   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10977
10978   if (tree_view->priv->hadjustment == NULL)
10979     gtk_tree_view_set_hadjustment (tree_view, NULL);
10980
10981   return tree_view->priv->hadjustment;
10982 }
10983
10984 /**
10985  * gtk_tree_view_set_hadjustment:
10986  * @tree_view: A #GtkTreeView
10987  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10988  *
10989  * Sets the #GtkAdjustment for the current horizontal aspect.
10990  **/
10991 void
10992 gtk_tree_view_set_hadjustment (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                                  adjustment,
10999                                  tree_view->priv->vadjustment);
11000
11001   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11002 }
11003
11004 /**
11005  * gtk_tree_view_get_vadjustment:
11006  * @tree_view: A #GtkTreeView
11007  *
11008  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11009  *
11010  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
11011  * used.
11012  **/
11013 GtkAdjustment *
11014 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11015 {
11016   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11017
11018   if (tree_view->priv->vadjustment == NULL)
11019     gtk_tree_view_set_vadjustment (tree_view, NULL);
11020
11021   return tree_view->priv->vadjustment;
11022 }
11023
11024 /**
11025  * gtk_tree_view_set_vadjustment:
11026  * @tree_view: A #GtkTreeView
11027  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11028  *
11029  * Sets the #GtkAdjustment for the current vertical aspect.
11030  **/
11031 void
11032 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11033                                GtkAdjustment *adjustment)
11034 {
11035   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11036
11037   gtk_tree_view_set_adjustments (tree_view,
11038                                  tree_view->priv->hadjustment,
11039                                  adjustment);
11040
11041   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11042 }
11043
11044 /* Column and header operations */
11045
11046 /**
11047  * gtk_tree_view_get_headers_visible:
11048  * @tree_view: A #GtkTreeView.
11049  *
11050  * Returns %TRUE if the headers on the @tree_view are visible.
11051  *
11052  * Return value: Whether the headers are visible or not.
11053  **/
11054 gboolean
11055 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11056 {
11057   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11058
11059   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11060 }
11061
11062 /**
11063  * gtk_tree_view_set_headers_visible:
11064  * @tree_view: A #GtkTreeView.
11065  * @headers_visible: %TRUE if the headers are visible
11066  *
11067  * Sets the visibility state of the headers.
11068  **/
11069 void
11070 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11071                                    gboolean     headers_visible)
11072 {
11073   gint x, y;
11074   GList *list;
11075   GtkTreeViewColumn *column;
11076   GtkAllocation allocation;
11077
11078   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11079
11080   headers_visible = !! headers_visible;
11081
11082   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11083     return;
11084
11085   if (headers_visible)
11086     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11087   else
11088     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11089
11090   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11091     {
11092       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11093       if (headers_visible)
11094         {
11095           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11096           gdk_window_move_resize (tree_view->priv->bin_window,
11097                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11098                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11099
11100           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11101             gtk_tree_view_map_buttons (tree_view);
11102         }
11103       else
11104         {
11105           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11106
11107           for (list = tree_view->priv->columns; list; list = list->next)
11108             {
11109               column = list->data;
11110               gtk_widget_unmap (column->button);
11111             }
11112           gdk_window_hide (tree_view->priv->header_window);
11113         }
11114     }
11115
11116   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11117   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11118   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11119   tree_view->priv->vadjustment->lower = 0;
11120   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11121   gtk_adjustment_changed (tree_view->priv->vadjustment);
11122
11123   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11124
11125   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11126 }
11127
11128 /**
11129  * gtk_tree_view_columns_autosize:
11130  * @tree_view: A #GtkTreeView.
11131  *
11132  * Resizes all columns to their optimal width. Only works after the
11133  * treeview has been realized.
11134  **/
11135 void
11136 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11137 {
11138   gboolean dirty = FALSE;
11139   GList *list;
11140   GtkTreeViewColumn *column;
11141
11142   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11143
11144   for (list = tree_view->priv->columns; list; list = list->next)
11145     {
11146       column = list->data;
11147       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11148         continue;
11149       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11150       dirty = TRUE;
11151     }
11152
11153   if (dirty)
11154     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11155 }
11156
11157 /**
11158  * gtk_tree_view_set_headers_clickable:
11159  * @tree_view: A #GtkTreeView.
11160  * @setting: %TRUE if the columns are clickable.
11161  *
11162  * Allow the column title buttons to be clicked.
11163  **/
11164 void
11165 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11166                                      gboolean   setting)
11167 {
11168   GList *list;
11169
11170   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11171
11172   for (list = tree_view->priv->columns; list; list = list->next)
11173     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11174
11175   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11176 }
11177
11178
11179 /**
11180  * gtk_tree_view_get_headers_clickable:
11181  * @tree_view: A #GtkTreeView.
11182  *
11183  * Returns whether all header columns are clickable.
11184  *
11185  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11186  *
11187  * Since: 2.10
11188  **/
11189 gboolean 
11190 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11191 {
11192   GList *list;
11193   
11194   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11195
11196   for (list = tree_view->priv->columns; list; list = list->next)
11197     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11198       return FALSE;
11199
11200   return TRUE;
11201 }
11202
11203 /**
11204  * gtk_tree_view_set_rules_hint
11205  * @tree_view: a #GtkTreeView
11206  * @setting: %TRUE if the tree requires reading across rows
11207  *
11208  * This function tells GTK+ that the user interface for your
11209  * application requires users to read across tree rows and associate
11210  * cells with one another. By default, GTK+ will then render the tree
11211  * with alternating row colors. Do <emphasis>not</emphasis> use it
11212  * just because you prefer the appearance of the ruled tree; that's a
11213  * question for the theme. Some themes will draw tree rows in
11214  * alternating colors even when rules are turned off, and users who
11215  * prefer that appearance all the time can choose those themes. You
11216  * should call this function only as a <emphasis>semantic</emphasis>
11217  * hint to the theme engine that your tree makes alternating colors
11218  * useful from a functional standpoint (since it has lots of columns,
11219  * generally).
11220  *
11221  **/
11222 void
11223 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11224                               gboolean      setting)
11225 {
11226   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11227
11228   setting = setting != FALSE;
11229
11230   if (tree_view->priv->has_rules != setting)
11231     {
11232       tree_view->priv->has_rules = setting;
11233       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11234     }
11235
11236   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11237 }
11238
11239 /**
11240  * gtk_tree_view_get_rules_hint
11241  * @tree_view: a #GtkTreeView
11242  *
11243  * Gets the setting set by gtk_tree_view_set_rules_hint().
11244  *
11245  * Return value: %TRUE if rules are useful for the user of this tree
11246  **/
11247 gboolean
11248 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11249 {
11250   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11251
11252   return tree_view->priv->has_rules;
11253 }
11254
11255 /* Public Column functions
11256  */
11257
11258 /**
11259  * gtk_tree_view_append_column:
11260  * @tree_view: A #GtkTreeView.
11261  * @column: The #GtkTreeViewColumn to add.
11262  *
11263  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11264  * mode enabled, then @column must have its "sizing" property set to be
11265  * GTK_TREE_VIEW_COLUMN_FIXED.
11266  *
11267  * Return value: The number of columns in @tree_view after appending.
11268  **/
11269 gint
11270 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11271                              GtkTreeViewColumn *column)
11272 {
11273   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11274   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11275   g_return_val_if_fail (column->tree_view == NULL, -1);
11276
11277   return gtk_tree_view_insert_column (tree_view, column, -1);
11278 }
11279
11280
11281 /**
11282  * gtk_tree_view_remove_column:
11283  * @tree_view: A #GtkTreeView.
11284  * @column: The #GtkTreeViewColumn to remove.
11285  *
11286  * Removes @column from @tree_view.
11287  *
11288  * Return value: The number of columns in @tree_view after removing.
11289  **/
11290 gint
11291 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11292                              GtkTreeViewColumn *column)
11293 {
11294   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11295   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11296   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11297
11298   if (tree_view->priv->focus_column == column)
11299     tree_view->priv->focus_column = NULL;
11300
11301   if (tree_view->priv->edited_column == column)
11302     {
11303       gtk_tree_view_stop_editing (tree_view, TRUE);
11304
11305       /* no need to, but just to be sure ... */
11306       tree_view->priv->edited_column = NULL;
11307     }
11308
11309   if (tree_view->priv->expander_column == column)
11310     tree_view->priv->expander_column = NULL;
11311
11312   g_signal_handlers_disconnect_by_func (column,
11313                                         G_CALLBACK (column_sizing_notify),
11314                                         tree_view);
11315
11316   _gtk_tree_view_column_unset_tree_view (column);
11317
11318   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11319   tree_view->priv->n_columns--;
11320
11321   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11322     {
11323       GList *list;
11324
11325       _gtk_tree_view_column_unrealize_button (column);
11326       for (list = tree_view->priv->columns; list; list = list->next)
11327         {
11328           GtkTreeViewColumn *tmp_column;
11329
11330           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11331           if (tmp_column->visible)
11332             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11333         }
11334
11335       if (tree_view->priv->n_columns == 0 &&
11336           gtk_tree_view_get_headers_visible (tree_view))
11337         gdk_window_hide (tree_view->priv->header_window);
11338
11339       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11340     }
11341
11342   g_object_unref (column);
11343   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11344
11345   return tree_view->priv->n_columns;
11346 }
11347
11348 /**
11349  * gtk_tree_view_insert_column:
11350  * @tree_view: A #GtkTreeView.
11351  * @column: The #GtkTreeViewColumn to be inserted.
11352  * @position: The position to insert @column in.
11353  *
11354  * This inserts the @column into the @tree_view at @position.  If @position is
11355  * -1, then the column is inserted at the end. If @tree_view has
11356  * "fixed_height" mode enabled, then @column must have its "sizing" property
11357  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11358  *
11359  * Return value: The number of columns in @tree_view after insertion.
11360  **/
11361 gint
11362 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11363                              GtkTreeViewColumn *column,
11364                              gint               position)
11365 {
11366   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11367   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11368   g_return_val_if_fail (column->tree_view == NULL, -1);
11369
11370   if (tree_view->priv->fixed_height_mode)
11371     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11372                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11373
11374   g_object_ref_sink (column);
11375
11376   if (tree_view->priv->n_columns == 0 &&
11377       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11378       gtk_tree_view_get_headers_visible (tree_view))
11379     {
11380       gdk_window_show (tree_view->priv->header_window);
11381     }
11382
11383   g_signal_connect (column, "notify::sizing",
11384                     G_CALLBACK (column_sizing_notify), tree_view);
11385
11386   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11387                                             column, position);
11388   tree_view->priv->n_columns++;
11389
11390   _gtk_tree_view_column_set_tree_view (column, tree_view);
11391
11392   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11393     {
11394       GList *list;
11395
11396       _gtk_tree_view_column_realize_button (column);
11397
11398       for (list = tree_view->priv->columns; list; list = list->next)
11399         {
11400           column = GTK_TREE_VIEW_COLUMN (list->data);
11401           if (column->visible)
11402             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11403         }
11404       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11405     }
11406
11407   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11408
11409   return tree_view->priv->n_columns;
11410 }
11411
11412 /**
11413  * gtk_tree_view_insert_column_with_attributes:
11414  * @tree_view: A #GtkTreeView
11415  * @position: The position to insert the new column in.
11416  * @title: The title to set the header to.
11417  * @cell: The #GtkCellRenderer.
11418  * @Varargs: A %NULL-terminated list of attributes.
11419  *
11420  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11421  * @position.  If @position is -1, then the newly created column is inserted at
11422  * the end.  The column is initialized with the attributes given. If @tree_view
11423  * has "fixed_height" mode enabled, then the new column will have its sizing
11424  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11425  *
11426  * Return value: The number of columns in @tree_view after insertion.
11427  **/
11428 gint
11429 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11430                                              gint             position,
11431                                              const gchar     *title,
11432                                              GtkCellRenderer *cell,
11433                                              ...)
11434 {
11435   GtkTreeViewColumn *column;
11436   gchar *attribute;
11437   va_list args;
11438   gint column_id;
11439
11440   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11441
11442   column = gtk_tree_view_column_new ();
11443   if (tree_view->priv->fixed_height_mode)
11444     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11445
11446   gtk_tree_view_column_set_title (column, title);
11447   gtk_tree_view_column_pack_start (column, cell, TRUE);
11448
11449   va_start (args, cell);
11450
11451   attribute = va_arg (args, gchar *);
11452
11453   while (attribute != NULL)
11454     {
11455       column_id = va_arg (args, gint);
11456       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11457       attribute = va_arg (args, gchar *);
11458     }
11459
11460   va_end (args);
11461
11462   gtk_tree_view_insert_column (tree_view, column, position);
11463
11464   return tree_view->priv->n_columns;
11465 }
11466
11467 /**
11468  * gtk_tree_view_insert_column_with_data_func:
11469  * @tree_view: a #GtkTreeView
11470  * @position: Position to insert, -1 for append
11471  * @title: column title
11472  * @cell: cell renderer for column
11473  * @func: function to set attributes of cell renderer
11474  * @data: data for @func
11475  * @dnotify: destroy notifier for @data
11476  *
11477  * Convenience function that inserts a new column into the #GtkTreeView
11478  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11479  * attributes (normally using data from the model). See also
11480  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11481  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11482  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11483  *
11484  * Return value: number of columns in the tree view post-insert
11485  **/
11486 gint
11487 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11488                                              gint                       position,
11489                                              const gchar               *title,
11490                                              GtkCellRenderer           *cell,
11491                                              GtkTreeCellDataFunc        func,
11492                                              gpointer                   data,
11493                                              GDestroyNotify             dnotify)
11494 {
11495   GtkTreeViewColumn *column;
11496
11497   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11498
11499   column = gtk_tree_view_column_new ();
11500   if (tree_view->priv->fixed_height_mode)
11501     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11502
11503   gtk_tree_view_column_set_title (column, title);
11504   gtk_tree_view_column_pack_start (column, cell, TRUE);
11505   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11506
11507   gtk_tree_view_insert_column (tree_view, column, position);
11508
11509   return tree_view->priv->n_columns;
11510 }
11511
11512 /**
11513  * gtk_tree_view_get_column:
11514  * @tree_view: A #GtkTreeView.
11515  * @n: The position of the column, counting from 0.
11516  *
11517  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11518  *
11519  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11520  * range of columns.
11521  **/
11522 GtkTreeViewColumn *
11523 gtk_tree_view_get_column (GtkTreeView *tree_view,
11524                           gint         n)
11525 {
11526   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11527
11528   if (n < 0 || n >= tree_view->priv->n_columns)
11529     return NULL;
11530
11531   if (tree_view->priv->columns == NULL)
11532     return NULL;
11533
11534   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11535 }
11536
11537 /**
11538  * gtk_tree_view_get_columns:
11539  * @tree_view: A #GtkTreeView
11540  *
11541  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11542  * The returned list must be freed with g_list_free ().
11543  *
11544  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11545  **/
11546 GList *
11547 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11548 {
11549   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11550
11551   return g_list_copy (tree_view->priv->columns);
11552 }
11553
11554 /**
11555  * gtk_tree_view_move_column_after:
11556  * @tree_view: A #GtkTreeView
11557  * @column: The #GtkTreeViewColumn to be moved.
11558  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11559  *
11560  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11561  * @column is placed in the first position.
11562  **/
11563 void
11564 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11565                                  GtkTreeViewColumn *column,
11566                                  GtkTreeViewColumn *base_column)
11567 {
11568   GList *column_list_el, *base_el = NULL;
11569
11570   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11571
11572   column_list_el = g_list_find (tree_view->priv->columns, column);
11573   g_return_if_fail (column_list_el != NULL);
11574
11575   if (base_column)
11576     {
11577       base_el = g_list_find (tree_view->priv->columns, base_column);
11578       g_return_if_fail (base_el != NULL);
11579     }
11580
11581   if (column_list_el->prev == base_el)
11582     return;
11583
11584   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11585   if (base_el == NULL)
11586     {
11587       column_list_el->prev = NULL;
11588       column_list_el->next = tree_view->priv->columns;
11589       if (column_list_el->next)
11590         column_list_el->next->prev = column_list_el;
11591       tree_view->priv->columns = column_list_el;
11592     }
11593   else
11594     {
11595       column_list_el->prev = base_el;
11596       column_list_el->next = base_el->next;
11597       if (column_list_el->next)
11598         column_list_el->next->prev = column_list_el;
11599       base_el->next = column_list_el;
11600     }
11601
11602   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11603     {
11604       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11605       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11606     }
11607
11608   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11609 }
11610
11611 /**
11612  * gtk_tree_view_set_expander_column:
11613  * @tree_view: A #GtkTreeView
11614  * @column: %NULL, or the column to draw the expander arrow at.
11615  *
11616  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11617  * If @column is %NULL, then the expander arrow is always at the first 
11618  * visible column.
11619  *
11620  * If you do not want expander arrow to appear in your tree, set the 
11621  * expander column to a hidden column.
11622  **/
11623 void
11624 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11625                                    GtkTreeViewColumn *column)
11626 {
11627   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11628   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11629
11630   if (tree_view->priv->expander_column != column)
11631     {
11632       GList *list;
11633
11634       if (column)
11635         {
11636           /* Confirm that column is in tree_view */
11637           for (list = tree_view->priv->columns; list; list = list->next)
11638             if (list->data == column)
11639               break;
11640           g_return_if_fail (list != NULL);
11641         }
11642
11643       tree_view->priv->expander_column = column;
11644       g_object_notify (G_OBJECT (tree_view), "expander-column");
11645     }
11646 }
11647
11648 /**
11649  * gtk_tree_view_get_expander_column:
11650  * @tree_view: A #GtkTreeView
11651  *
11652  * Returns the column that is the current expander column.  This
11653  * column has the expander arrow drawn next to it.
11654  *
11655  * Return value: The expander column.
11656  **/
11657 GtkTreeViewColumn *
11658 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11659 {
11660   GList *list;
11661
11662   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11663
11664   for (list = tree_view->priv->columns; list; list = list->next)
11665     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11666       return (GtkTreeViewColumn *) list->data;
11667   return NULL;
11668 }
11669
11670
11671 /**
11672  * gtk_tree_view_set_column_drag_function:
11673  * @tree_view: A #GtkTreeView.
11674  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11675  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11676  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11677  *
11678  * Sets a user function for determining where a column may be dropped when
11679  * dragged.  This function is called on every column pair in turn at the
11680  * beginning of a column drag to determine where a drop can take place.  The
11681  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11682  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11683  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11684  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11685  * @tree_view reverts to the default behavior of allowing all columns to be
11686  * dropped everywhere.
11687  **/
11688 void
11689 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11690                                         GtkTreeViewColumnDropFunc  func,
11691                                         gpointer                   user_data,
11692                                         GDestroyNotify             destroy)
11693 {
11694   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11695
11696   if (tree_view->priv->column_drop_func_data_destroy)
11697     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11698
11699   tree_view->priv->column_drop_func = func;
11700   tree_view->priv->column_drop_func_data = user_data;
11701   tree_view->priv->column_drop_func_data_destroy = destroy;
11702 }
11703
11704 /**
11705  * gtk_tree_view_scroll_to_point:
11706  * @tree_view: a #GtkTreeView
11707  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11708  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11709  *
11710  * Scrolls the tree view such that the top-left corner of the visible
11711  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11712  * in tree coordinates.  The @tree_view must be realized before
11713  * this function is called.  If it isn't, you probably want to be
11714  * using gtk_tree_view_scroll_to_cell().
11715  *
11716  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11717  **/
11718 void
11719 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11720                                gint         tree_x,
11721                                gint         tree_y)
11722 {
11723   GtkAdjustment *hadj;
11724   GtkAdjustment *vadj;
11725
11726   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11727   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11728
11729   hadj = tree_view->priv->hadjustment;
11730   vadj = tree_view->priv->vadjustment;
11731
11732   if (tree_x != -1)
11733     gtk_adjustment_set_value (hadj, tree_x);
11734   if (tree_y != -1)
11735     gtk_adjustment_set_value (vadj, tree_y);
11736 }
11737
11738 /**
11739  * gtk_tree_view_scroll_to_cell:
11740  * @tree_view: A #GtkTreeView.
11741  * @path: (allow-none): The path of the row to move to, or %NULL.
11742  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11743  * @use_align: whether to use alignment arguments, or %FALSE.
11744  * @row_align: The vertical alignment of the row specified by @path.
11745  * @col_align: The horizontal alignment of the column specified by @column.
11746  *
11747  * Moves the alignments of @tree_view to the position specified by @column and
11748  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11749  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11750  * or @path need to be non-%NULL.  @row_align determines where the row is
11751  * placed, and @col_align determines where @column is placed.  Both are expected
11752  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11753  * right/bottom alignment, 0.5 means center.
11754  *
11755  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11756  * tree does the minimum amount of work to scroll the cell onto the screen.
11757  * This means that the cell will be scrolled to the edge closest to its current
11758  * position.  If the cell is currently visible on the screen, nothing is done.
11759  *
11760  * This function only works if the model is set, and @path is a valid row on the
11761  * model.  If the model changes before the @tree_view is realized, the centered
11762  * path will be modified to reflect this change.
11763  **/
11764 void
11765 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11766                               GtkTreePath       *path,
11767                               GtkTreeViewColumn *column,
11768                               gboolean           use_align,
11769                               gfloat             row_align,
11770                               gfloat             col_align)
11771 {
11772   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11773   g_return_if_fail (tree_view->priv->model != NULL);
11774   g_return_if_fail (tree_view->priv->tree != NULL);
11775   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11776   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11777   g_return_if_fail (path != NULL || column != NULL);
11778
11779 #if 0
11780   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11781            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11782 #endif
11783   row_align = CLAMP (row_align, 0.0, 1.0);
11784   col_align = CLAMP (col_align, 0.0, 1.0);
11785
11786
11787   /* Note: Despite the benefits that come from having one code path for the
11788    * scrolling code, we short-circuit validate_visible_area's immplementation as
11789    * it is much slower than just going to the point.
11790    */
11791   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11792       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11793       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11794       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11795     {
11796       if (tree_view->priv->scroll_to_path)
11797         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11798
11799       tree_view->priv->scroll_to_path = NULL;
11800       tree_view->priv->scroll_to_column = NULL;
11801
11802       if (path)
11803         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11804       if (column)
11805         tree_view->priv->scroll_to_column = column;
11806       tree_view->priv->scroll_to_use_align = use_align;
11807       tree_view->priv->scroll_to_row_align = row_align;
11808       tree_view->priv->scroll_to_col_align = col_align;
11809
11810       install_presize_handler (tree_view);
11811     }
11812   else
11813     {
11814       GdkRectangle cell_rect;
11815       GdkRectangle vis_rect;
11816       gint dest_x, dest_y;
11817
11818       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11819       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11820
11821       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11822
11823       dest_x = vis_rect.x;
11824       dest_y = vis_rect.y;
11825
11826       if (column)
11827         {
11828           if (use_align)
11829             {
11830               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11831             }
11832           else
11833             {
11834               if (cell_rect.x < vis_rect.x)
11835                 dest_x = cell_rect.x;
11836               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11837                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11838             }
11839         }
11840
11841       if (path)
11842         {
11843           if (use_align)
11844             {
11845               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11846               dest_y = MAX (dest_y, 0);
11847             }
11848           else
11849             {
11850               if (cell_rect.y < vis_rect.y)
11851                 dest_y = cell_rect.y;
11852               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11853                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11854             }
11855         }
11856
11857       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11858     }
11859 }
11860
11861 /**
11862  * gtk_tree_view_row_activated:
11863  * @tree_view: A #GtkTreeView
11864  * @path: The #GtkTreePath to be activated.
11865  * @column: The #GtkTreeViewColumn to be activated.
11866  *
11867  * Activates the cell determined by @path and @column.
11868  **/
11869 void
11870 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11871                              GtkTreePath       *path,
11872                              GtkTreeViewColumn *column)
11873 {
11874   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11875
11876   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11877 }
11878
11879
11880 static void
11881 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11882                                           GtkRBNode *node,
11883                                           gpointer   data)
11884 {
11885   GtkTreeView *tree_view = data;
11886
11887   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11888       node->children)
11889     {
11890       GtkTreePath *path;
11891       GtkTreeIter iter;
11892
11893       path = _gtk_tree_view_find_path (tree_view, tree, node);
11894       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11895
11896       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11897
11898       gtk_tree_path_free (path);
11899     }
11900
11901   if (node->children)
11902     _gtk_rbtree_traverse (node->children,
11903                           node->children->root,
11904                           G_PRE_ORDER,
11905                           gtk_tree_view_expand_all_emission_helper,
11906                           tree_view);
11907 }
11908
11909 /**
11910  * gtk_tree_view_expand_all:
11911  * @tree_view: A #GtkTreeView.
11912  *
11913  * Recursively expands all nodes in the @tree_view.
11914  **/
11915 void
11916 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11917 {
11918   GtkTreePath *path;
11919   GtkRBTree *tree;
11920   GtkRBNode *node;
11921
11922   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11923
11924   if (tree_view->priv->tree == NULL)
11925     return;
11926
11927   path = gtk_tree_path_new_first ();
11928   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11929
11930   while (node)
11931     {
11932       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11933       node = _gtk_rbtree_next (tree, node);
11934       gtk_tree_path_next (path);
11935   }
11936
11937   gtk_tree_path_free (path);
11938 }
11939
11940 /* Timeout to animate the expander during expands and collapses */
11941 static gboolean
11942 expand_collapse_timeout (gpointer data)
11943 {
11944   return do_expand_collapse (data);
11945 }
11946
11947 static void
11948 add_expand_collapse_timeout (GtkTreeView *tree_view,
11949                              GtkRBTree   *tree,
11950                              GtkRBNode   *node,
11951                              gboolean     expand)
11952 {
11953   if (tree_view->priv->expand_collapse_timeout != 0)
11954     return;
11955
11956   tree_view->priv->expand_collapse_timeout =
11957       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11958   tree_view->priv->expanded_collapsed_tree = tree;
11959   tree_view->priv->expanded_collapsed_node = node;
11960
11961   if (expand)
11962     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11963   else
11964     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11965 }
11966
11967 static void
11968 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11969 {
11970   if (tree_view->priv->expand_collapse_timeout)
11971     {
11972       g_source_remove (tree_view->priv->expand_collapse_timeout);
11973       tree_view->priv->expand_collapse_timeout = 0;
11974     }
11975
11976   if (tree_view->priv->expanded_collapsed_node != NULL)
11977     {
11978       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11979       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11980
11981       tree_view->priv->expanded_collapsed_node = NULL;
11982     }
11983 }
11984
11985 static void
11986 cancel_arrow_animation (GtkTreeView *tree_view)
11987 {
11988   if (tree_view->priv->expand_collapse_timeout)
11989     {
11990       while (do_expand_collapse (tree_view));
11991
11992       remove_expand_collapse_timeout (tree_view);
11993     }
11994 }
11995
11996 static gboolean
11997 do_expand_collapse (GtkTreeView *tree_view)
11998 {
11999   GtkRBNode *node;
12000   GtkRBTree *tree;
12001   gboolean expanding;
12002   gboolean redraw;
12003
12004   redraw = FALSE;
12005   expanding = TRUE;
12006
12007   node = tree_view->priv->expanded_collapsed_node;
12008   tree = tree_view->priv->expanded_collapsed_tree;
12009
12010   if (node->children == NULL)
12011     expanding = FALSE;
12012
12013   if (expanding)
12014     {
12015       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12016         {
12017           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12018           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12019
12020           redraw = TRUE;
12021
12022         }
12023       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12024         {
12025           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12026
12027           redraw = TRUE;
12028         }
12029     }
12030   else
12031     {
12032       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12033         {
12034           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12035           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12036
12037           redraw = TRUE;
12038         }
12039       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12040         {
12041           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12042
12043           redraw = TRUE;
12044
12045         }
12046     }
12047
12048   if (redraw)
12049     {
12050       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
12051
12052       return TRUE;
12053     }
12054
12055   return FALSE;
12056 }
12057
12058 /**
12059  * gtk_tree_view_collapse_all:
12060  * @tree_view: A #GtkTreeView.
12061  *
12062  * Recursively collapses all visible, expanded nodes in @tree_view.
12063  **/
12064 void
12065 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12066 {
12067   GtkRBTree *tree;
12068   GtkRBNode *node;
12069   GtkTreePath *path;
12070   gint *indices;
12071
12072   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12073
12074   if (tree_view->priv->tree == NULL)
12075     return;
12076
12077   path = gtk_tree_path_new ();
12078   gtk_tree_path_down (path);
12079   indices = gtk_tree_path_get_indices (path);
12080
12081   tree = tree_view->priv->tree;
12082   node = tree->root;
12083   while (node && node->left != tree->nil)
12084     node = node->left;
12085
12086   while (node)
12087     {
12088       if (node->children)
12089         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12090       indices[0]++;
12091       node = _gtk_rbtree_next (tree, node);
12092     }
12093
12094   gtk_tree_path_free (path);
12095 }
12096
12097 /**
12098  * gtk_tree_view_expand_to_path:
12099  * @tree_view: A #GtkTreeView.
12100  * @path: path to a row.
12101  *
12102  * Expands the row at @path. This will also expand all parent rows of
12103  * @path as necessary.
12104  *
12105  * Since: 2.2
12106  **/
12107 void
12108 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12109                               GtkTreePath *path)
12110 {
12111   gint i, depth;
12112   gint *indices;
12113   GtkTreePath *tmp;
12114
12115   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12116   g_return_if_fail (path != NULL);
12117
12118   depth = gtk_tree_path_get_depth (path);
12119   indices = gtk_tree_path_get_indices (path);
12120
12121   tmp = gtk_tree_path_new ();
12122   g_return_if_fail (tmp != NULL);
12123
12124   for (i = 0; i < depth; i++)
12125     {
12126       gtk_tree_path_append_index (tmp, indices[i]);
12127       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12128     }
12129
12130   gtk_tree_path_free (tmp);
12131 }
12132
12133 /* FIXME the bool return values for expand_row and collapse_row are
12134  * not analagous; they should be TRUE if the row had children and
12135  * was not already in the requested state.
12136  */
12137
12138
12139 static gboolean
12140 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12141                                GtkTreePath *path,
12142                                GtkRBTree   *tree,
12143                                GtkRBNode   *node,
12144                                gboolean     open_all,
12145                                gboolean     animate)
12146 {
12147   GtkTreeIter iter;
12148   GtkTreeIter temp;
12149   gboolean expand;
12150
12151   if (animate)
12152     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12153                   "gtk-enable-animations", &animate,
12154                   NULL);
12155
12156   remove_auto_expand_timeout (tree_view);
12157
12158   if (node->children && !open_all)
12159     return FALSE;
12160
12161   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12162     return FALSE;
12163
12164   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12165   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12166     return FALSE;
12167
12168
12169    if (node->children && open_all)
12170     {
12171       gboolean retval = FALSE;
12172       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12173
12174       gtk_tree_path_append_index (tmp_path, 0);
12175       tree = node->children;
12176       node = tree->root;
12177       while (node->left != tree->nil)
12178         node = node->left;
12179       /* try to expand the children */
12180       do
12181         {
12182          gboolean t;
12183          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12184                                             TRUE, animate);
12185          if (t)
12186            retval = TRUE;
12187
12188          gtk_tree_path_next (tmp_path);
12189          node = _gtk_rbtree_next (tree, node);
12190        }
12191       while (node != NULL);
12192
12193       gtk_tree_path_free (tmp_path);
12194
12195       return retval;
12196     }
12197
12198   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12199
12200   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12201     return FALSE;
12202
12203   if (expand)
12204     return FALSE;
12205
12206   node->children = _gtk_rbtree_new ();
12207   node->children->parent_tree = tree;
12208   node->children->parent_node = node;
12209
12210   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12211
12212   gtk_tree_view_build_tree (tree_view,
12213                             node->children,
12214                             &temp,
12215                             gtk_tree_path_get_depth (path) + 1,
12216                             open_all);
12217
12218   remove_expand_collapse_timeout (tree_view);
12219
12220   if (animate)
12221     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12222
12223   install_presize_handler (tree_view);
12224
12225   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12226   if (open_all && node->children)
12227     {
12228       _gtk_rbtree_traverse (node->children,
12229                             node->children->root,
12230                             G_PRE_ORDER,
12231                             gtk_tree_view_expand_all_emission_helper,
12232                             tree_view);
12233     }
12234   return TRUE;
12235 }
12236
12237
12238 /**
12239  * gtk_tree_view_expand_row:
12240  * @tree_view: a #GtkTreeView
12241  * @path: path to a row
12242  * @open_all: whether to recursively expand, or just expand immediate children
12243  *
12244  * Opens the row so its children are visible.
12245  *
12246  * Return value: %TRUE if the row existed and had children
12247  **/
12248 gboolean
12249 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12250                           GtkTreePath *path,
12251                           gboolean     open_all)
12252 {
12253   GtkRBTree *tree;
12254   GtkRBNode *node;
12255
12256   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12257   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12258   g_return_val_if_fail (path != NULL, FALSE);
12259
12260   if (_gtk_tree_view_find_node (tree_view,
12261                                 path,
12262                                 &tree,
12263                                 &node))
12264     return FALSE;
12265
12266   if (tree != NULL)
12267     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12268   else
12269     return FALSE;
12270 }
12271
12272 static gboolean
12273 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12274                                  GtkTreePath *path,
12275                                  GtkRBTree   *tree,
12276                                  GtkRBNode   *node,
12277                                  gboolean     animate)
12278 {
12279   GtkTreeIter iter;
12280   GtkTreeIter children;
12281   gboolean collapse;
12282   gint x, y;
12283   GList *list;
12284   GdkWindow *child, *parent;
12285
12286   if (animate)
12287     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12288                   "gtk-enable-animations", &animate,
12289                   NULL);
12290
12291   remove_auto_expand_timeout (tree_view);
12292
12293   if (node->children == NULL)
12294     return FALSE;
12295
12296   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12297
12298   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12299
12300   if (collapse)
12301     return FALSE;
12302
12303   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12304    * a chance to prelight the correct node below */
12305
12306   if (tree_view->priv->prelight_tree)
12307     {
12308       GtkRBTree *parent_tree;
12309       GtkRBNode *parent_node;
12310
12311       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12312       parent_node = tree_view->priv->prelight_tree->parent_node;
12313       while (parent_tree)
12314         {
12315           if (parent_tree == tree && parent_node == node)
12316             {
12317               ensure_unprelighted (tree_view);
12318               break;
12319             }
12320           parent_node = parent_tree->parent_node;
12321           parent_tree = parent_tree->parent_tree;
12322         }
12323     }
12324
12325   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12326
12327   for (list = tree_view->priv->columns; list; list = list->next)
12328     {
12329       GtkTreeViewColumn *column = list->data;
12330
12331       if (column->visible == FALSE)
12332         continue;
12333       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12334         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12335     }
12336
12337   if (tree_view->priv->destroy_count_func)
12338     {
12339       GtkTreePath *child_path;
12340       gint child_count = 0;
12341       child_path = gtk_tree_path_copy (path);
12342       gtk_tree_path_down (child_path);
12343       if (node->children)
12344         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12345       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12346       gtk_tree_path_free (child_path);
12347     }
12348
12349   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12350     {
12351       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12352
12353       if (gtk_tree_path_is_ancestor (path, cursor_path))
12354         {
12355           gtk_tree_row_reference_free (tree_view->priv->cursor);
12356           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12357                                                                       tree_view->priv->model,
12358                                                                       path);
12359         }
12360       gtk_tree_path_free (cursor_path);
12361     }
12362
12363   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12364     {
12365       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12366       if (gtk_tree_path_is_ancestor (path, anchor_path))
12367         {
12368           gtk_tree_row_reference_free (tree_view->priv->anchor);
12369           tree_view->priv->anchor = NULL;
12370         }
12371       gtk_tree_path_free (anchor_path);
12372     }
12373
12374   /* Stop a pending double click */
12375   tree_view->priv->last_button_x = -1;
12376   tree_view->priv->last_button_y = -1;
12377
12378   remove_expand_collapse_timeout (tree_view);
12379
12380   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12381     {
12382       _gtk_rbtree_remove (node->children);
12383       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12384     }
12385   else
12386     _gtk_rbtree_remove (node->children);
12387   
12388   if (animate)
12389     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12390   
12391   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12392     {
12393       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12394     }
12395
12396   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12397
12398   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12399     {
12400       /* now that we've collapsed all rows, we want to try to set the prelight
12401        * again. To do this, we fake a motion event and send it to ourselves. */
12402
12403       child = tree_view->priv->bin_window;
12404       parent = gdk_window_get_parent (child);
12405
12406       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12407         {
12408           GdkEventMotion event;
12409           gint child_x, child_y;
12410
12411           gdk_window_get_position (child, &child_x, &child_y);
12412
12413           event.window = tree_view->priv->bin_window;
12414           event.x = x - child_x;
12415           event.y = y - child_y;
12416
12417           /* despite the fact this isn't a real event, I'm almost positive it will
12418            * never trigger a drag event.  maybe_drag is the only function that uses
12419            * more than just event.x and event.y. */
12420           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12421         }
12422     }
12423
12424   return TRUE;
12425 }
12426
12427 /**
12428  * gtk_tree_view_collapse_row:
12429  * @tree_view: a #GtkTreeView
12430  * @path: path to a row in the @tree_view
12431  *
12432  * Collapses a row (hides its child rows, if they exist).
12433  *
12434  * Return value: %TRUE if the row was collapsed.
12435  **/
12436 gboolean
12437 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12438                             GtkTreePath *path)
12439 {
12440   GtkRBTree *tree;
12441   GtkRBNode *node;
12442
12443   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12444   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12445   g_return_val_if_fail (path != NULL, FALSE);
12446
12447   if (_gtk_tree_view_find_node (tree_view,
12448                                 path,
12449                                 &tree,
12450                                 &node))
12451     return FALSE;
12452
12453   if (tree == NULL || node->children == NULL)
12454     return FALSE;
12455
12456   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12457 }
12458
12459 static void
12460 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12461                                         GtkRBTree              *tree,
12462                                         GtkTreePath            *path,
12463                                         GtkTreeViewMappingFunc  func,
12464                                         gpointer                user_data)
12465 {
12466   GtkRBNode *node;
12467
12468   if (tree == NULL || tree->root == NULL)
12469     return;
12470
12471   node = tree->root;
12472
12473   while (node && node->left != tree->nil)
12474     node = node->left;
12475
12476   while (node)
12477     {
12478       if (node->children)
12479         {
12480           (* func) (tree_view, path, user_data);
12481           gtk_tree_path_down (path);
12482           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12483           gtk_tree_path_up (path);
12484         }
12485       gtk_tree_path_next (path);
12486       node = _gtk_rbtree_next (tree, node);
12487     }
12488 }
12489
12490 /**
12491  * gtk_tree_view_map_expanded_rows:
12492  * @tree_view: A #GtkTreeView
12493  * @func: A function to be called
12494  * @data: User data to be passed to the function.
12495  *
12496  * Calls @func on all expanded rows.
12497  **/
12498 void
12499 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12500                                  GtkTreeViewMappingFunc  func,
12501                                  gpointer                user_data)
12502 {
12503   GtkTreePath *path;
12504
12505   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12506   g_return_if_fail (func != NULL);
12507
12508   path = gtk_tree_path_new_first ();
12509
12510   gtk_tree_view_map_expanded_rows_helper (tree_view,
12511                                           tree_view->priv->tree,
12512                                           path, func, user_data);
12513
12514   gtk_tree_path_free (path);
12515 }
12516
12517 /**
12518  * gtk_tree_view_row_expanded:
12519  * @tree_view: A #GtkTreeView.
12520  * @path: A #GtkTreePath to test expansion state.
12521  *
12522  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12523  *
12524  * Return value: %TRUE if #path is expanded.
12525  **/
12526 gboolean
12527 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12528                             GtkTreePath *path)
12529 {
12530   GtkRBTree *tree;
12531   GtkRBNode *node;
12532
12533   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12534   g_return_val_if_fail (path != NULL, FALSE);
12535
12536   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12537
12538   if (node == NULL)
12539     return FALSE;
12540
12541   return (node->children != NULL);
12542 }
12543
12544 /**
12545  * gtk_tree_view_get_reorderable:
12546  * @tree_view: a #GtkTreeView
12547  *
12548  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12549  * gtk_tree_view_set_reorderable().
12550  *
12551  * Return value: %TRUE if the tree can be reordered.
12552  **/
12553 gboolean
12554 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12555 {
12556   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12557
12558   return tree_view->priv->reorderable;
12559 }
12560
12561 /**
12562  * gtk_tree_view_set_reorderable:
12563  * @tree_view: A #GtkTreeView.
12564  * @reorderable: %TRUE, if the tree can be reordered.
12565  *
12566  * This function is a convenience function to allow you to reorder
12567  * models that support the #GtkDragSourceIface and the
12568  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12569  * these.  If @reorderable is %TRUE, then the user can reorder the
12570  * model by dragging and dropping rows. The developer can listen to
12571  * these changes by connecting to the model's row_inserted and
12572  * row_deleted signals. The reordering is implemented by setting up
12573  * the tree view as a drag source and destination. Therefore, drag and
12574  * drop can not be used in a reorderable view for any other purpose.
12575  *
12576  * This function does not give you any degree of control over the order -- any
12577  * reordering is allowed.  If more control is needed, you should probably
12578  * handle drag and drop manually.
12579  **/
12580 void
12581 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12582                                gboolean     reorderable)
12583 {
12584   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12585
12586   reorderable = reorderable != FALSE;
12587
12588   if (tree_view->priv->reorderable == reorderable)
12589     return;
12590
12591   if (reorderable)
12592     {
12593       const GtkTargetEntry row_targets[] = {
12594         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12595       };
12596
12597       gtk_tree_view_enable_model_drag_source (tree_view,
12598                                               GDK_BUTTON1_MASK,
12599                                               row_targets,
12600                                               G_N_ELEMENTS (row_targets),
12601                                               GDK_ACTION_MOVE);
12602       gtk_tree_view_enable_model_drag_dest (tree_view,
12603                                             row_targets,
12604                                             G_N_ELEMENTS (row_targets),
12605                                             GDK_ACTION_MOVE);
12606     }
12607   else
12608     {
12609       gtk_tree_view_unset_rows_drag_source (tree_view);
12610       gtk_tree_view_unset_rows_drag_dest (tree_view);
12611     }
12612
12613   tree_view->priv->reorderable = reorderable;
12614
12615   g_object_notify (G_OBJECT (tree_view), "reorderable");
12616 }
12617
12618 static void
12619 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12620                                GtkTreePath     *path,
12621                                gboolean         clear_and_select,
12622                                gboolean         clamp_node)
12623 {
12624   GtkRBTree *tree = NULL;
12625   GtkRBNode *node = NULL;
12626
12627   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12628     {
12629       GtkTreePath *cursor_path;
12630       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12631       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12632       gtk_tree_path_free (cursor_path);
12633     }
12634
12635   gtk_tree_row_reference_free (tree_view->priv->cursor);
12636   tree_view->priv->cursor = NULL;
12637
12638   /* One cannot set the cursor on a separator.   Also, if
12639    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12640    * before finding the tree and node belonging to path.  The
12641    * path maps to a non-existing path and we will silently bail out.
12642    * We unset tree and node to avoid further processing.
12643    */
12644   if (!row_is_separator (tree_view, NULL, path)
12645       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12646     {
12647       tree_view->priv->cursor =
12648           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12649                                             tree_view->priv->model,
12650                                             path);
12651     }
12652   else
12653     {
12654       tree = NULL;
12655       node = NULL;
12656     }
12657
12658   if (tree != NULL)
12659     {
12660       GtkRBTree *new_tree = NULL;
12661       GtkRBNode *new_node = NULL;
12662
12663       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12664         {
12665           GtkTreeSelectMode mode = 0;
12666
12667           if (tree_view->priv->ctrl_pressed)
12668             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12669           if (tree_view->priv->shift_pressed)
12670             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12671
12672           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12673                                                     node, tree, path, mode,
12674                                                     FALSE);
12675         }
12676
12677       /* We have to re-find tree and node here again, somebody might have
12678        * cleared the node or the whole tree in the GtkTreeSelection::changed
12679        * callback. If the nodes differ we bail out here.
12680        */
12681       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12682
12683       if (tree != new_tree || node != new_node)
12684         return;
12685
12686       if (clamp_node)
12687         {
12688           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12689           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12690         }
12691     }
12692
12693   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12694 }
12695
12696 /**
12697  * gtk_tree_view_get_cursor:
12698  * @tree_view: A #GtkTreeView
12699  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12700  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12701  *
12702  * Fills in @path and @focus_column with the current path and focus column.  If
12703  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12704  * currently has focus, then *@focus_column will be %NULL.
12705  *
12706  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12707  * you are done with it.
12708  **/
12709 void
12710 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12711                           GtkTreePath       **path,
12712                           GtkTreeViewColumn **focus_column)
12713 {
12714   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12715
12716   if (path)
12717     {
12718       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12719         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12720       else
12721         *path = NULL;
12722     }
12723
12724   if (focus_column)
12725     {
12726       *focus_column = tree_view->priv->focus_column;
12727     }
12728 }
12729
12730 /**
12731  * gtk_tree_view_set_cursor:
12732  * @tree_view: A #GtkTreeView
12733  * @path: A #GtkTreePath
12734  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12735  * @start_editing: %TRUE if the specified cell should start being edited.
12736  *
12737  * Sets the current keyboard focus to be at @path, and selects it.  This is
12738  * useful when you want to focus the user's attention on a particular row.  If
12739  * @focus_column is not %NULL, then focus is given to the column specified by 
12740  * it. Additionally, if @focus_column is specified, and @start_editing is 
12741  * %TRUE, then editing should be started in the specified cell.  
12742  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12743  * in order to give keyboard focus to the widget.  Please note that editing 
12744  * can only happen when the widget is realized.
12745  *
12746  * If @path is invalid for @model, the current cursor (if any) will be unset
12747  * and the function will return without failing.
12748  **/
12749 void
12750 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12751                           GtkTreePath       *path,
12752                           GtkTreeViewColumn *focus_column,
12753                           gboolean           start_editing)
12754 {
12755   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12756                                     NULL, start_editing);
12757 }
12758
12759 /**
12760  * gtk_tree_view_set_cursor_on_cell:
12761  * @tree_view: A #GtkTreeView
12762  * @path: A #GtkTreePath
12763  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12764  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12765  * @start_editing: %TRUE if the specified cell should start being edited.
12766  *
12767  * Sets the current keyboard focus to be at @path, and selects it.  This is
12768  * useful when you want to focus the user's attention on a particular row.  If
12769  * @focus_column is not %NULL, then focus is given to the column specified by
12770  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12771  * contains 2 or more editable or activatable cells, then focus is given to
12772  * the cell specified by @focus_cell. Additionally, if @focus_column is
12773  * specified, and @start_editing is %TRUE, then editing should be started in
12774  * the specified cell.  This function is often followed by
12775  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12776  * widget.  Please note that editing can only happen when the widget is
12777  * realized.
12778  *
12779  * If @path is invalid for @model, the current cursor (if any) will be unset
12780  * and the function will return without failing.
12781  *
12782  * Since: 2.2
12783  **/
12784 void
12785 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12786                                   GtkTreePath       *path,
12787                                   GtkTreeViewColumn *focus_column,
12788                                   GtkCellRenderer   *focus_cell,
12789                                   gboolean           start_editing)
12790 {
12791   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12792   g_return_if_fail (path != NULL);
12793   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12794
12795   if (!tree_view->priv->model)
12796     return;
12797
12798   if (focus_cell)
12799     {
12800       g_return_if_fail (focus_column);
12801       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12802     }
12803
12804   /* cancel the current editing, if it exists */
12805   if (tree_view->priv->edited_column &&
12806       tree_view->priv->edited_column->editable_widget)
12807     gtk_tree_view_stop_editing (tree_view, TRUE);
12808
12809   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12810
12811   if (focus_column && focus_column->visible)
12812     {
12813       GList *list;
12814       gboolean column_in_tree = FALSE;
12815
12816       for (list = tree_view->priv->columns; list; list = list->next)
12817         if (list->data == focus_column)
12818           {
12819             column_in_tree = TRUE;
12820             break;
12821           }
12822       g_return_if_fail (column_in_tree);
12823       tree_view->priv->focus_column = focus_column;
12824       if (focus_cell)
12825         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12826       if (start_editing)
12827         gtk_tree_view_start_editing (tree_view, path);
12828     }
12829 }
12830
12831 /**
12832  * gtk_tree_view_get_bin_window:
12833  * @tree_view: A #GtkTreeView
12834  * 
12835  * Returns the window that @tree_view renders to.  This is used primarily to
12836  * compare to <literal>event->window</literal> to confirm that the event on
12837  * @tree_view is on the right window.
12838  * 
12839  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12840  **/
12841 GdkWindow *
12842 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12843 {
12844   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12845
12846   return tree_view->priv->bin_window;
12847 }
12848
12849 /**
12850  * gtk_tree_view_get_path_at_pos:
12851  * @tree_view: A #GtkTreeView.
12852  * @x: The x position to be identified (relative to bin_window).
12853  * @y: The y position to be identified (relative to bin_window).
12854  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12855  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12856  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12857  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12858  *
12859  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12860  * (please see gtk_tree_view_get_bin_window()).
12861  * That is, @x and @y are relative to an events coordinates. @x and @y must
12862  * come from an event on the @tree_view only where <literal>event->window ==
12863  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12864  * things like popup menus. If @path is non-%NULL, then it will be filled
12865  * with the #GtkTreePath at that point.  This path should be freed with
12866  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12867  * with the column at that point.  @cell_x and @cell_y return the coordinates
12868  * relative to the cell background (i.e. the @background_area passed to
12869  * gtk_cell_renderer_render()).  This function is only meaningful if
12870  * @tree_view is realized.  Therefore this function will always return %FALSE
12871  * if @tree_view is not realized or does not have a model.
12872  *
12873  * For converting widget coordinates (eg. the ones you get from
12874  * GtkWidget::query-tooltip), please see
12875  * gtk_tree_view_convert_widget_to_bin_window_coords().
12876  *
12877  * Return value: %TRUE if a row exists at that coordinate.
12878  **/
12879 gboolean
12880 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12881                                gint                x,
12882                                gint                y,
12883                                GtkTreePath       **path,
12884                                GtkTreeViewColumn **column,
12885                                gint               *cell_x,
12886                                gint               *cell_y)
12887 {
12888   GtkRBTree *tree;
12889   GtkRBNode *node;
12890   gint y_offset;
12891
12892   g_return_val_if_fail (tree_view != NULL, FALSE);
12893
12894   if (path)
12895     *path = NULL;
12896   if (column)
12897     *column = NULL;
12898
12899   if (tree_view->priv->bin_window == NULL)
12900     return FALSE;
12901
12902   if (tree_view->priv->tree == NULL)
12903     return FALSE;
12904
12905   if (x > tree_view->priv->hadjustment->upper)
12906     return FALSE;
12907
12908   if (x < 0 || y < 0)
12909     return FALSE;
12910
12911   if (column || cell_x)
12912     {
12913       GtkTreeViewColumn *tmp_column;
12914       GtkTreeViewColumn *last_column = NULL;
12915       GList *list;
12916       gint remaining_x = x;
12917       gboolean found = FALSE;
12918       gboolean rtl;
12919
12920       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12921       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12922            list;
12923            list = (rtl ? list->prev : list->next))
12924         {
12925           tmp_column = list->data;
12926
12927           if (tmp_column->visible == FALSE)
12928             continue;
12929
12930           last_column = tmp_column;
12931           if (remaining_x <= tmp_column->width)
12932             {
12933               found = TRUE;
12934
12935               if (column)
12936                 *column = tmp_column;
12937
12938               if (cell_x)
12939                 *cell_x = remaining_x;
12940
12941               break;
12942             }
12943           remaining_x -= tmp_column->width;
12944         }
12945
12946       /* If found is FALSE and there is a last_column, then it the remainder
12947        * space is in that area
12948        */
12949       if (!found)
12950         {
12951           if (last_column)
12952             {
12953               if (column)
12954                 *column = last_column;
12955               
12956               if (cell_x)
12957                 *cell_x = last_column->width + remaining_x;
12958             }
12959           else
12960             {
12961               return FALSE;
12962             }
12963         }
12964     }
12965
12966   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12967                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12968                                       &tree, &node);
12969
12970   if (tree == NULL)
12971     return FALSE;
12972
12973   if (cell_y)
12974     *cell_y = y_offset;
12975
12976   if (path)
12977     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12978
12979   return TRUE;
12980 }
12981
12982
12983 /**
12984  * gtk_tree_view_get_cell_area:
12985  * @tree_view: a #GtkTreeView
12986  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12987  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12988  * @rect: rectangle to fill with cell rect
12989  *
12990  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12991  * row specified by @path and the column specified by @column.  If @path is
12992  * %NULL, or points to a path not currently displayed, the @y and @height fields
12993  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12994  * fields will be filled with 0.  The sum of all cell rects does not cover the
12995  * entire tree; there are extra pixels in between rows, for example. The
12996  * returned rectangle is equivalent to the @cell_area passed to
12997  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12998  * realized.
12999  **/
13000 void
13001 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13002                              GtkTreePath        *path,
13003                              GtkTreeViewColumn  *column,
13004                              GdkRectangle       *rect)
13005 {
13006   GtkAllocation allocation;
13007   GtkRBTree *tree = NULL;
13008   GtkRBNode *node = NULL;
13009   gint vertical_separator;
13010   gint horizontal_separator;
13011
13012   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13013   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13014   g_return_if_fail (rect != NULL);
13015   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
13016   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13017
13018   gtk_widget_style_get (GTK_WIDGET (tree_view),
13019                         "vertical-separator", &vertical_separator,
13020                         "horizontal-separator", &horizontal_separator,
13021                         NULL);
13022
13023   rect->x = 0;
13024   rect->y = 0;
13025   rect->width = 0;
13026   rect->height = 0;
13027
13028   if (column)
13029     {
13030       gtk_widget_get_allocation (column->button, &allocation);
13031       rect->x = allocation.x + horizontal_separator/2;
13032       rect->width = allocation.width - horizontal_separator;
13033     }
13034
13035   if (path)
13036     {
13037       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13038
13039       /* Get vertical coords */
13040       if ((!ret && tree == NULL) || ret)
13041         return;
13042
13043       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
13044       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
13045
13046       if (column &&
13047           gtk_tree_view_is_expander_column (tree_view, column))
13048         {
13049           gint depth = gtk_tree_path_get_depth (path);
13050           gboolean rtl;
13051
13052           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13053
13054           if (!rtl)
13055             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13056           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13057
13058           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
13059             {
13060               if (!rtl)
13061                 rect->x += depth * tree_view->priv->expander_size;
13062               rect->width -= depth * tree_view->priv->expander_size;
13063             }
13064
13065           rect->width = MAX (rect->width, 0);
13066         }
13067     }
13068 }
13069
13070 /**
13071  * gtk_tree_view_get_background_area:
13072  * @tree_view: a #GtkTreeView
13073  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13074  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13075  * @rect: rectangle to fill with cell background rect
13076  *
13077  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13078  * row specified by @path and the column specified by @column.  If @path is
13079  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13080  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13081  * fields will be filled with 0.  The returned rectangle is equivalent to the
13082  * @background_area passed to gtk_cell_renderer_render().  These background
13083  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13084  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13085  * itself, excluding surrounding borders and the tree expander area.
13086  *
13087  **/
13088 void
13089 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13090                                    GtkTreePath        *path,
13091                                    GtkTreeViewColumn  *column,
13092                                    GdkRectangle       *rect)
13093 {
13094   GtkRBTree *tree = NULL;
13095   GtkRBNode *node = NULL;
13096
13097   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13098   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13099   g_return_if_fail (rect != NULL);
13100
13101   rect->x = 0;
13102   rect->y = 0;
13103   rect->width = 0;
13104   rect->height = 0;
13105
13106   if (path)
13107     {
13108       /* Get vertical coords */
13109
13110       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13111           tree == NULL)
13112         return;
13113
13114       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13115
13116       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13117     }
13118
13119   if (column)
13120     {
13121       gint x2 = 0;
13122
13123       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13124       rect->width = x2 - rect->x;
13125     }
13126 }
13127
13128 /**
13129  * gtk_tree_view_get_visible_rect:
13130  * @tree_view: a #GtkTreeView
13131  * @visible_rect: rectangle to fill
13132  *
13133  * Fills @visible_rect with the currently-visible region of the
13134  * buffer, in tree coordinates. Convert to bin_window coordinates with
13135  * gtk_tree_view_convert_tree_to_bin_window_coords().
13136  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13137  * scrollable area of the tree.
13138  **/
13139 void
13140 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13141                                 GdkRectangle *visible_rect)
13142 {
13143   GtkAllocation allocation;
13144   GtkWidget *widget;
13145
13146   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13147
13148   widget = GTK_WIDGET (tree_view);
13149
13150   if (visible_rect)
13151     {
13152       gtk_widget_get_allocation (widget, &allocation);
13153       visible_rect->x = tree_view->priv->hadjustment->value;
13154       visible_rect->y = tree_view->priv->vadjustment->value;
13155       visible_rect->width = allocation.width;
13156       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13157     }
13158 }
13159
13160 /**
13161  * gtk_tree_view_convert_widget_to_tree_coords:
13162  * @tree_view: a #GtkTreeView
13163  * @wx: X coordinate relative to the widget
13164  * @wy: Y coordinate relative to the widget
13165  * @tx: return location for tree X coordinate
13166  * @ty: return location for tree Y coordinate
13167  *
13168  * Converts widget coordinates to coordinates for the
13169  * tree (the full scrollable area of the tree).
13170  *
13171  * Since: 2.12
13172  **/
13173 void
13174 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13175                                              gint         wx,
13176                                              gint         wy,
13177                                              gint        *tx,
13178                                              gint        *ty)
13179 {
13180   gint x, y;
13181
13182   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13183
13184   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13185                                                      wx, wy,
13186                                                      &x, &y);
13187   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13188                                                    x, y,
13189                                                    tx, ty);
13190 }
13191
13192 /**
13193  * gtk_tree_view_convert_tree_to_widget_coords:
13194  * @tree_view: a #GtkTreeView
13195  * @tx: X coordinate relative to the tree
13196  * @ty: Y coordinate relative to the tree
13197  * @wx: return location for widget X coordinate
13198  * @wy: return location for widget Y coordinate
13199  *
13200  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13201  * to widget coordinates.
13202  *
13203  * Since: 2.12
13204  **/
13205 void
13206 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13207                                              gint         tx,
13208                                              gint         ty,
13209                                              gint        *wx,
13210                                              gint        *wy)
13211 {
13212   gint x, y;
13213
13214   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13215
13216   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13217                                                    tx, ty,
13218                                                    &x, &y);
13219   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13220                                                      x, y,
13221                                                      wx, wy);
13222 }
13223
13224 /**
13225  * gtk_tree_view_convert_widget_to_bin_window_coords:
13226  * @tree_view: a #GtkTreeView
13227  * @wx: X coordinate relative to the widget
13228  * @wy: Y coordinate relative to the widget
13229  * @bx: return location for bin_window X coordinate
13230  * @by: return location for bin_window Y coordinate
13231  *
13232  * Converts widget coordinates to coordinates for the bin_window
13233  * (see gtk_tree_view_get_bin_window()).
13234  *
13235  * Since: 2.12
13236  **/
13237 void
13238 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13239                                                    gint         wx,
13240                                                    gint         wy,
13241                                                    gint        *bx,
13242                                                    gint        *by)
13243 {
13244   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13245
13246   if (bx)
13247     *bx = wx + tree_view->priv->hadjustment->value;
13248   if (by)
13249     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13250 }
13251
13252 /**
13253  * gtk_tree_view_convert_bin_window_to_widget_coords:
13254  * @tree_view: a #GtkTreeView
13255  * @bx: bin_window X coordinate
13256  * @by: bin_window Y coordinate
13257  * @wx: return location for widget X coordinate
13258  * @wy: return location for widget Y coordinate
13259  *
13260  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13261  * to widget relative coordinates.
13262  *
13263  * Since: 2.12
13264  **/
13265 void
13266 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13267                                                    gint         bx,
13268                                                    gint         by,
13269                                                    gint        *wx,
13270                                                    gint        *wy)
13271 {
13272   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13273
13274   if (wx)
13275     *wx = bx - tree_view->priv->hadjustment->value;
13276   if (wy)
13277     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13278 }
13279
13280 /**
13281  * gtk_tree_view_convert_tree_to_bin_window_coords:
13282  * @tree_view: a #GtkTreeView
13283  * @tx: tree X coordinate
13284  * @ty: tree Y coordinate
13285  * @bx: return location for X coordinate relative to bin_window
13286  * @by: return location for Y coordinate relative to bin_window
13287  *
13288  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13289  * to bin_window coordinates.
13290  *
13291  * Since: 2.12
13292  **/
13293 void
13294 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13295                                                  gint         tx,
13296                                                  gint         ty,
13297                                                  gint        *bx,
13298                                                  gint        *by)
13299 {
13300   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13301
13302   if (bx)
13303     *bx = tx;
13304   if (by)
13305     *by = ty - tree_view->priv->dy;
13306 }
13307
13308 /**
13309  * gtk_tree_view_convert_bin_window_to_tree_coords:
13310  * @tree_view: a #GtkTreeView
13311  * @bx: X coordinate relative to bin_window
13312  * @by: Y coordinate relative to bin_window
13313  * @tx: return location for tree X coordinate
13314  * @ty: return location for tree Y coordinate
13315  *
13316  * Converts bin_window coordinates to coordinates for the
13317  * tree (the full scrollable area of the tree).
13318  *
13319  * Since: 2.12
13320  **/
13321 void
13322 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13323                                                  gint         bx,
13324                                                  gint         by,
13325                                                  gint        *tx,
13326                                                  gint        *ty)
13327 {
13328   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13329
13330   if (tx)
13331     *tx = bx;
13332   if (ty)
13333     *ty = by + tree_view->priv->dy;
13334 }
13335
13336
13337
13338 /**
13339  * gtk_tree_view_get_visible_range:
13340  * @tree_view: A #GtkTreeView
13341  * @start_path: (allow-none): Return location for start of region, or %NULL.
13342  * @end_path: (allow-none): Return location for end of region, or %NULL.
13343  *
13344  * Sets @start_path and @end_path to be the first and last visible path.
13345  * Note that there may be invisible paths in between.
13346  *
13347  * The paths should be freed with gtk_tree_path_free() after use.
13348  *
13349  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13350  *
13351  * Since: 2.8
13352  **/
13353 gboolean
13354 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13355                                  GtkTreePath **start_path,
13356                                  GtkTreePath **end_path)
13357 {
13358   GtkRBTree *tree;
13359   GtkRBNode *node;
13360   gboolean retval;
13361   
13362   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13363
13364   if (!tree_view->priv->tree)
13365     return FALSE;
13366
13367   retval = TRUE;
13368
13369   if (start_path)
13370     {
13371       _gtk_rbtree_find_offset (tree_view->priv->tree,
13372                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13373                                &tree, &node);
13374       if (node)
13375         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13376       else
13377         retval = FALSE;
13378     }
13379
13380   if (end_path)
13381     {
13382       gint y;
13383
13384       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13385         y = tree_view->priv->height - 1;
13386       else
13387         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13388
13389       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13390       if (node)
13391         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13392       else
13393         retval = FALSE;
13394     }
13395
13396   return retval;
13397 }
13398
13399 static void
13400 unset_reorderable (GtkTreeView *tree_view)
13401 {
13402   if (tree_view->priv->reorderable)
13403     {
13404       tree_view->priv->reorderable = FALSE;
13405       g_object_notify (G_OBJECT (tree_view), "reorderable");
13406     }
13407 }
13408
13409 /**
13410  * gtk_tree_view_enable_model_drag_source:
13411  * @tree_view: a #GtkTreeView
13412  * @start_button_mask: Mask of allowed buttons to start drag
13413  * @targets: the table of targets that the drag will support
13414  * @n_targets: the number of items in @targets
13415  * @actions: the bitmask of possible actions for a drag from this
13416  *    widget
13417  *
13418  * Turns @tree_view into a drag source for automatic DND. Calling this
13419  * method sets #GtkTreeView:reorderable to %FALSE.
13420  **/
13421 void
13422 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13423                                         GdkModifierType           start_button_mask,
13424                                         const GtkTargetEntry     *targets,
13425                                         gint                      n_targets,
13426                                         GdkDragAction             actions)
13427 {
13428   TreeViewDragInfo *di;
13429
13430   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13431
13432   gtk_drag_source_set (GTK_WIDGET (tree_view),
13433                        0,
13434                        targets,
13435                        n_targets,
13436                        actions);
13437
13438   di = ensure_info (tree_view);
13439
13440   di->start_button_mask = start_button_mask;
13441   di->source_actions = actions;
13442   di->source_set = TRUE;
13443
13444   unset_reorderable (tree_view);
13445 }
13446
13447 /**
13448  * gtk_tree_view_enable_model_drag_dest:
13449  * @tree_view: a #GtkTreeView
13450  * @targets: the table of targets that the drag will support
13451  * @n_targets: the number of items in @targets
13452  * @actions: the bitmask of possible actions for a drag from this
13453  *    widget
13454  * 
13455  * Turns @tree_view into a drop destination for automatic DND. Calling
13456  * this method sets #GtkTreeView:reorderable to %FALSE.
13457  **/
13458 void
13459 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13460                                       const GtkTargetEntry     *targets,
13461                                       gint                      n_targets,
13462                                       GdkDragAction             actions)
13463 {
13464   TreeViewDragInfo *di;
13465
13466   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13467
13468   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13469                      0,
13470                      targets,
13471                      n_targets,
13472                      actions);
13473
13474   di = ensure_info (tree_view);
13475   di->dest_set = TRUE;
13476
13477   unset_reorderable (tree_view);
13478 }
13479
13480 /**
13481  * gtk_tree_view_unset_rows_drag_source:
13482  * @tree_view: a #GtkTreeView
13483  *
13484  * Undoes the effect of
13485  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13486  * #GtkTreeView:reorderable to %FALSE.
13487  **/
13488 void
13489 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13490 {
13491   TreeViewDragInfo *di;
13492
13493   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13494
13495   di = get_info (tree_view);
13496
13497   if (di)
13498     {
13499       if (di->source_set)
13500         {
13501           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13502           di->source_set = FALSE;
13503         }
13504
13505       if (!di->dest_set && !di->source_set)
13506         remove_info (tree_view);
13507     }
13508   
13509   unset_reorderable (tree_view);
13510 }
13511
13512 /**
13513  * gtk_tree_view_unset_rows_drag_dest:
13514  * @tree_view: a #GtkTreeView
13515  *
13516  * Undoes the effect of
13517  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13518  * #GtkTreeView:reorderable to %FALSE.
13519  **/
13520 void
13521 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13522 {
13523   TreeViewDragInfo *di;
13524
13525   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13526
13527   di = get_info (tree_view);
13528
13529   if (di)
13530     {
13531       if (di->dest_set)
13532         {
13533           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13534           di->dest_set = FALSE;
13535         }
13536
13537       if (!di->dest_set && !di->source_set)
13538         remove_info (tree_view);
13539     }
13540
13541   unset_reorderable (tree_view);
13542 }
13543
13544 /**
13545  * gtk_tree_view_set_drag_dest_row:
13546  * @tree_view: a #GtkTreeView
13547  * @path: (allow-none): The path of the row to highlight, or %NULL.
13548  * @pos: Specifies whether to drop before, after or into the row
13549  * 
13550  * Sets the row that is highlighted for feedback.
13551  **/
13552 void
13553 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13554                                  GtkTreePath            *path,
13555                                  GtkTreeViewDropPosition pos)
13556 {
13557   GtkTreePath *current_dest;
13558
13559   /* Note; this function is exported to allow a custom DND
13560    * implementation, so it can't touch TreeViewDragInfo
13561    */
13562
13563   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13564
13565   current_dest = NULL;
13566
13567   if (tree_view->priv->drag_dest_row)
13568     {
13569       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13570       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13571     }
13572
13573   /* special case a drop on an empty model */
13574   tree_view->priv->empty_view_drop = 0;
13575
13576   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13577       && gtk_tree_path_get_depth (path) == 1
13578       && gtk_tree_path_get_indices (path)[0] == 0)
13579     {
13580       gint n_children;
13581
13582       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13583                                                    NULL);
13584
13585       if (!n_children)
13586         tree_view->priv->empty_view_drop = 1;
13587     }
13588
13589   tree_view->priv->drag_dest_pos = pos;
13590
13591   if (path)
13592     {
13593       tree_view->priv->drag_dest_row =
13594         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13595       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13596     }
13597   else
13598     tree_view->priv->drag_dest_row = NULL;
13599
13600   if (current_dest)
13601     {
13602       GtkRBTree *tree, *new_tree;
13603       GtkRBNode *node, *new_node;
13604
13605       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13606       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13607
13608       if (tree && node)
13609         {
13610           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13611           if (new_tree && new_node)
13612             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13613
13614           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13615           if (new_tree && new_node)
13616             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13617         }
13618       gtk_tree_path_free (current_dest);
13619     }
13620 }
13621
13622 /**
13623  * gtk_tree_view_get_drag_dest_row:
13624  * @tree_view: a #GtkTreeView
13625  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13626  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13627  * 
13628  * Gets information about the row that is highlighted for feedback.
13629  **/
13630 void
13631 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13632                                  GtkTreePath             **path,
13633                                  GtkTreeViewDropPosition  *pos)
13634 {
13635   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13636
13637   if (path)
13638     {
13639       if (tree_view->priv->drag_dest_row)
13640         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13641       else
13642         {
13643           if (tree_view->priv->empty_view_drop)
13644             *path = gtk_tree_path_new_from_indices (0, -1);
13645           else
13646             *path = NULL;
13647         }
13648     }
13649
13650   if (pos)
13651     *pos = tree_view->priv->drag_dest_pos;
13652 }
13653
13654 /**
13655  * gtk_tree_view_get_dest_row_at_pos:
13656  * @tree_view: a #GtkTreeView
13657  * @drag_x: the position to determine the destination row for
13658  * @drag_y: the position to determine the destination row for
13659  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13660  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13661  * 
13662  * Determines the destination row for a given position.  @drag_x and
13663  * @drag_y are expected to be in widget coordinates.  This function is only
13664  * meaningful if @tree_view is realized.  Therefore this function will always
13665  * return %FALSE if @tree_view is not realized or does not have a model.
13666  * 
13667  * Return value: whether there is a row at the given position, %TRUE if this
13668  * is indeed the case.
13669  **/
13670 gboolean
13671 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13672                                    gint                     drag_x,
13673                                    gint                     drag_y,
13674                                    GtkTreePath            **path,
13675                                    GtkTreeViewDropPosition *pos)
13676 {
13677   gint cell_y;
13678   gint bin_x, bin_y;
13679   gdouble offset_into_row;
13680   gdouble third;
13681   GdkRectangle cell;
13682   GtkTreeViewColumn *column = NULL;
13683   GtkTreePath *tmp_path = NULL;
13684
13685   /* Note; this function is exported to allow a custom DND
13686    * implementation, so it can't touch TreeViewDragInfo
13687    */
13688
13689   g_return_val_if_fail (tree_view != NULL, FALSE);
13690   g_return_val_if_fail (drag_x >= 0, FALSE);
13691   g_return_val_if_fail (drag_y >= 0, FALSE);
13692
13693   if (path)
13694     *path = NULL;
13695
13696   if (tree_view->priv->bin_window == NULL)
13697     return FALSE;
13698
13699   if (tree_view->priv->tree == NULL)
13700     return FALSE;
13701
13702   /* If in the top third of a row, we drop before that row; if
13703    * in the bottom third, drop after that row; if in the middle,
13704    * and the row has children, drop into the row.
13705    */
13706   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13707                                                      &bin_x, &bin_y);
13708
13709   if (!gtk_tree_view_get_path_at_pos (tree_view,
13710                                       bin_x,
13711                                       bin_y,
13712                                       &tmp_path,
13713                                       &column,
13714                                       NULL,
13715                                       &cell_y))
13716     return FALSE;
13717
13718   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13719                                      &cell);
13720
13721   offset_into_row = cell_y;
13722
13723   if (path)
13724     *path = tmp_path;
13725   else
13726     gtk_tree_path_free (tmp_path);
13727
13728   tmp_path = NULL;
13729
13730   third = cell.height / 3.0;
13731
13732   if (pos)
13733     {
13734       if (offset_into_row < third)
13735         {
13736           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13737         }
13738       else if (offset_into_row < (cell.height / 2.0))
13739         {
13740           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13741         }
13742       else if (offset_into_row < third * 2.0)
13743         {
13744           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13745         }
13746       else
13747         {
13748           *pos = GTK_TREE_VIEW_DROP_AFTER;
13749         }
13750     }
13751
13752   return TRUE;
13753 }
13754
13755
13756
13757 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13758 /**
13759  * gtk_tree_view_create_row_drag_icon:
13760  * @tree_view: a #GtkTreeView
13761  * @path: a #GtkTreePath in @tree_view
13762  *
13763  * Creates a #GdkPixmap representation of the row at @path.  
13764  * This image is used for a drag icon.
13765  *
13766  * Return value: a newly-allocated pixmap of the drag icon.
13767  **/
13768 GdkPixmap *
13769 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13770                                     GtkTreePath  *path)
13771 {
13772   GtkTreeIter   iter;
13773   GtkRBTree    *tree;
13774   GtkRBNode    *node;
13775   GtkStyle *style;
13776   gint cell_offset;
13777   GList *list;
13778   GdkRectangle background_area;
13779   GdkRectangle expose_area;
13780   GtkWidget *widget;
13781   gint depth;
13782   /* start drawing inside the black outline */
13783   gint x = 1, y = 1;
13784   GdkDrawable *drawable;
13785   gint bin_window_width;
13786   gboolean is_separator = FALSE;
13787   gboolean rtl;
13788   cairo_t *cr;
13789
13790   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13791   g_return_val_if_fail (path != NULL, NULL);
13792
13793   widget = GTK_WIDGET (tree_view);
13794
13795   if (!gtk_widget_get_realized (widget))
13796     return NULL;
13797
13798   depth = gtk_tree_path_get_depth (path);
13799
13800   _gtk_tree_view_find_node (tree_view,
13801                             path,
13802                             &tree,
13803                             &node);
13804
13805   if (tree == NULL)
13806     return NULL;
13807
13808   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13809                                 &iter,
13810                                 path))
13811     return NULL;
13812
13813   style = gtk_widget_get_style (widget);
13814
13815   is_separator = row_is_separator (tree_view, &iter, NULL);
13816
13817   cell_offset = x;
13818
13819   background_area.y = y;
13820   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13821
13822   gdk_drawable_get_size (tree_view->priv->bin_window,
13823                          &bin_window_width, NULL);
13824
13825   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13826                              bin_window_width + 2,
13827                              background_area.height + 2,
13828                              -1);
13829
13830   expose_area.x = 0;
13831   expose_area.y = 0;
13832   expose_area.width = bin_window_width + 2;
13833   expose_area.height = background_area.height + 2;
13834
13835   cr = gdk_cairo_create (drawable);
13836   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13837   cairo_paint (cr);
13838
13839   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13840
13841   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13842       list;
13843       list = (rtl ? list->prev : list->next))
13844     {
13845       GtkTreeViewColumn *column = list->data;
13846       GdkRectangle cell_area;
13847       gint vertical_separator;
13848
13849       if (!column->visible)
13850         continue;
13851
13852       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13853                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13854                                                node->children?TRUE:FALSE);
13855
13856       background_area.x = cell_offset;
13857       background_area.width = column->width;
13858
13859       gtk_widget_style_get (widget,
13860                             "vertical-separator", &vertical_separator,
13861                             NULL);
13862
13863       cell_area = background_area;
13864
13865       cell_area.y += vertical_separator / 2;
13866       cell_area.height -= vertical_separator;
13867
13868       if (gtk_tree_view_is_expander_column (tree_view, column))
13869         {
13870           if (!rtl)
13871             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13872           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13873
13874           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13875             {
13876               if (!rtl)
13877                 cell_area.x += depth * tree_view->priv->expander_size;
13878               cell_area.width -= depth * tree_view->priv->expander_size;
13879             }
13880         }
13881
13882       if (gtk_tree_view_column_cell_is_visible (column))
13883         {
13884           if (is_separator)
13885             gtk_paint_hline (style,
13886                              drawable,
13887                              GTK_STATE_NORMAL,
13888                              &cell_area,
13889                              widget,
13890                              NULL,
13891                              cell_area.x,
13892                              cell_area.x + cell_area.width,
13893                              cell_area.y + cell_area.height / 2);
13894           else
13895             _gtk_tree_view_column_cell_render (column,
13896                                                drawable,
13897                                                &background_area,
13898                                                &cell_area,
13899                                                &expose_area,
13900                                                0);
13901         }
13902       cell_offset += column->width;
13903     }
13904
13905   cairo_set_source_rgb (cr, 0, 0, 0);
13906   cairo_rectangle (cr, 
13907                    0.5, 0.5, 
13908                    bin_window_width + 1,
13909                    background_area.height + 1);
13910   cairo_set_line_width (cr, 1.0);
13911   cairo_stroke (cr);
13912
13913   cairo_destroy (cr);
13914
13915   return drawable;
13916 }
13917
13918
13919 /**
13920  * gtk_tree_view_set_destroy_count_func:
13921  * @tree_view: A #GtkTreeView
13922  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13923  * @data: (allow-none): User data to be passed to @func, or %NULL
13924  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13925  *
13926  * This function should almost never be used.  It is meant for private use by
13927  * ATK for determining the number of visible children that are removed when the
13928  * user collapses a row, or a row is deleted.
13929  **/
13930 void
13931 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13932                                       GtkTreeDestroyCountFunc  func,
13933                                       gpointer                 data,
13934                                       GDestroyNotify           destroy)
13935 {
13936   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13937
13938   if (tree_view->priv->destroy_count_destroy)
13939     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13940
13941   tree_view->priv->destroy_count_func = func;
13942   tree_view->priv->destroy_count_data = data;
13943   tree_view->priv->destroy_count_destroy = destroy;
13944 }
13945
13946
13947 /*
13948  * Interactive search
13949  */
13950
13951 /**
13952  * gtk_tree_view_set_enable_search:
13953  * @tree_view: A #GtkTreeView
13954  * @enable_search: %TRUE, if the user can search interactively
13955  *
13956  * If @enable_search is set, then the user can type in text to search through
13957  * the tree interactively (this is sometimes called "typeahead find").
13958  * 
13959  * Note that even if this is %FALSE, the user can still initiate a search 
13960  * using the "start-interactive-search" key binding.
13961  */
13962 void
13963 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13964                                  gboolean     enable_search)
13965 {
13966   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13967
13968   enable_search = !!enable_search;
13969   
13970   if (tree_view->priv->enable_search != enable_search)
13971     {
13972        tree_view->priv->enable_search = enable_search;
13973        g_object_notify (G_OBJECT (tree_view), "enable-search");
13974     }
13975 }
13976
13977 /**
13978  * gtk_tree_view_get_enable_search:
13979  * @tree_view: A #GtkTreeView
13980  *
13981  * Returns whether or not the tree allows to start interactive searching 
13982  * by typing in text.
13983  *
13984  * Return value: whether or not to let the user search interactively
13985  */
13986 gboolean
13987 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13988 {
13989   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13990
13991   return tree_view->priv->enable_search;
13992 }
13993
13994
13995 /**
13996  * gtk_tree_view_get_search_column:
13997  * @tree_view: A #GtkTreeView
13998  *
13999  * Gets the column searched on by the interactive search code.
14000  *
14001  * Return value: the column the interactive search code searches in.
14002  */
14003 gint
14004 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14005 {
14006   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14007
14008   return (tree_view->priv->search_column);
14009 }
14010
14011 /**
14012  * gtk_tree_view_set_search_column:
14013  * @tree_view: A #GtkTreeView
14014  * @column: the column of the model to search in, or -1 to disable searching
14015  *
14016  * Sets @column as the column where the interactive search code should
14017  * search in for the current model. 
14018  * 
14019  * If the search column is set, users can use the "start-interactive-search"
14020  * key binding to bring up search popup. The enable-search property controls
14021  * whether simply typing text will also start an interactive search.
14022  *
14023  * Note that @column refers to a column of the current model. The search 
14024  * column is reset to -1 when the model is changed.
14025  */
14026 void
14027 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14028                                  gint         column)
14029 {
14030   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14031   g_return_if_fail (column >= -1);
14032
14033   if (tree_view->priv->search_column == column)
14034     return;
14035
14036   tree_view->priv->search_column = column;
14037   g_object_notify (G_OBJECT (tree_view), "search-column");
14038 }
14039
14040 /**
14041  * gtk_tree_view_get_search_equal_func:
14042  * @tree_view: A #GtkTreeView
14043  *
14044  * Returns the compare function currently in use.
14045  *
14046  * Return value: the currently used compare function for the search code.
14047  */
14048
14049 GtkTreeViewSearchEqualFunc
14050 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14051 {
14052   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14053
14054   return tree_view->priv->search_equal_func;
14055 }
14056
14057 /**
14058  * gtk_tree_view_set_search_equal_func:
14059  * @tree_view: A #GtkTreeView
14060  * @search_equal_func: the compare function to use during the search
14061  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14062  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14063  *
14064  * Sets the compare function for the interactive search capabilities; note
14065  * that somewhat like strcmp() returning 0 for equality
14066  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14067  **/
14068 void
14069 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14070                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14071                                      gpointer                    search_user_data,
14072                                      GDestroyNotify              search_destroy)
14073 {
14074   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14075   g_return_if_fail (search_equal_func != NULL);
14076
14077   if (tree_view->priv->search_destroy)
14078     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14079
14080   tree_view->priv->search_equal_func = search_equal_func;
14081   tree_view->priv->search_user_data = search_user_data;
14082   tree_view->priv->search_destroy = search_destroy;
14083   if (tree_view->priv->search_equal_func == NULL)
14084     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14085 }
14086
14087 /**
14088  * gtk_tree_view_get_search_entry:
14089  * @tree_view: A #GtkTreeView
14090  *
14091  * Returns the #GtkEntry which is currently in use as interactive search
14092  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14093  * will be returned.
14094  *
14095  * Return value: the entry currently in use as search entry.
14096  *
14097  * Since: 2.10
14098  */
14099 GtkEntry *
14100 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14101 {
14102   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14103
14104   if (tree_view->priv->search_custom_entry_set)
14105     return GTK_ENTRY (tree_view->priv->search_entry);
14106
14107   return NULL;
14108 }
14109
14110 /**
14111  * gtk_tree_view_set_search_entry:
14112  * @tree_view: A #GtkTreeView
14113  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14114  *
14115  * Sets the entry which the interactive search code will use for this
14116  * @tree_view.  This is useful when you want to provide a search entry
14117  * in our interface at all time at a fixed position.  Passing %NULL for
14118  * @entry will make the interactive search code use the built-in popup
14119  * entry again.
14120  *
14121  * Since: 2.10
14122  */
14123 void
14124 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14125                                 GtkEntry    *entry)
14126 {
14127   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14128   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14129
14130   if (tree_view->priv->search_custom_entry_set)
14131     {
14132       if (tree_view->priv->search_entry_changed_id)
14133         {
14134           g_signal_handler_disconnect (tree_view->priv->search_entry,
14135                                        tree_view->priv->search_entry_changed_id);
14136           tree_view->priv->search_entry_changed_id = 0;
14137         }
14138       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14139                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14140                                             tree_view);
14141
14142       g_object_unref (tree_view->priv->search_entry);
14143     }
14144   else if (tree_view->priv->search_window)
14145     {
14146       gtk_widget_destroy (tree_view->priv->search_window);
14147
14148       tree_view->priv->search_window = NULL;
14149     }
14150
14151   if (entry)
14152     {
14153       tree_view->priv->search_entry = g_object_ref (entry);
14154       tree_view->priv->search_custom_entry_set = TRUE;
14155
14156       if (tree_view->priv->search_entry_changed_id == 0)
14157         {
14158           tree_view->priv->search_entry_changed_id =
14159             g_signal_connect (tree_view->priv->search_entry, "changed",
14160                               G_CALLBACK (gtk_tree_view_search_init),
14161                               tree_view);
14162         }
14163       
14164         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14165                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14166                           tree_view);
14167
14168         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14169     }
14170   else
14171     {
14172       tree_view->priv->search_entry = NULL;
14173       tree_view->priv->search_custom_entry_set = FALSE;
14174     }
14175 }
14176
14177 /**
14178  * gtk_tree_view_set_search_position_func:
14179  * @tree_view: A #GtkTreeView
14180  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14181  *    to use the default search position function
14182  * @data: (allow-none): user data to pass to @func, or %NULL
14183  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14184  *
14185  * Sets the function to use when positioning the search dialog.
14186  *
14187  * Since: 2.10
14188  **/
14189 void
14190 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14191                                         GtkTreeViewSearchPositionFunc  func,
14192                                         gpointer                       user_data,
14193                                         GDestroyNotify                 destroy)
14194 {
14195   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14196
14197   if (tree_view->priv->search_position_destroy)
14198     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14199
14200   tree_view->priv->search_position_func = func;
14201   tree_view->priv->search_position_user_data = user_data;
14202   tree_view->priv->search_position_destroy = destroy;
14203   if (tree_view->priv->search_position_func == NULL)
14204     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14205 }
14206
14207 /**
14208  * gtk_tree_view_get_search_position_func:
14209  * @tree_view: A #GtkTreeView
14210  *
14211  * Returns the positioning function currently in use.
14212  *
14213  * Return value: the currently used function for positioning the search dialog.
14214  *
14215  * Since: 2.10
14216  */
14217 GtkTreeViewSearchPositionFunc
14218 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14219 {
14220   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14221
14222   return tree_view->priv->search_position_func;
14223 }
14224
14225
14226 static void
14227 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14228                                   GtkTreeView *tree_view,
14229                                   GdkDevice   *device)
14230 {
14231   if (tree_view->priv->disable_popdown)
14232     return;
14233
14234   if (tree_view->priv->search_entry_changed_id)
14235     {
14236       g_signal_handler_disconnect (tree_view->priv->search_entry,
14237                                    tree_view->priv->search_entry_changed_id);
14238       tree_view->priv->search_entry_changed_id = 0;
14239     }
14240   if (tree_view->priv->typeselect_flush_timeout)
14241     {
14242       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14243       tree_view->priv->typeselect_flush_timeout = 0;
14244     }
14245         
14246   if (gtk_widget_get_visible (search_dialog))
14247     {
14248       /* send focus-in event */
14249       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14250       gtk_widget_hide (search_dialog);
14251       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14252       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14253     }
14254 }
14255
14256 static void
14257 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14258                                     GtkWidget   *search_dialog,
14259                                     gpointer     user_data)
14260 {
14261   gint x, y;
14262   gint tree_x, tree_y;
14263   gint tree_width, tree_height;
14264   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14265   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14266   GtkRequisition requisition;
14267   gint monitor_num;
14268   GdkRectangle monitor;
14269
14270   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14271   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14272
14273   gtk_widget_realize (search_dialog);
14274
14275   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14276   gdk_drawable_get_size (tree_window,
14277                          &tree_width,
14278                          &tree_height);
14279   gtk_size_request_get_size (GTK_SIZE_REQUEST (search_dialog),
14280                              &requisition, NULL);
14281
14282   if (tree_x + tree_width > gdk_screen_get_width (screen))
14283     x = gdk_screen_get_width (screen) - requisition.width;
14284   else if (tree_x + tree_width - requisition.width < 0)
14285     x = 0;
14286   else
14287     x = tree_x + tree_width - requisition.width;
14288
14289   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14290     y = gdk_screen_get_height (screen) - requisition.height;
14291   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14292     y = 0;
14293   else
14294     y = tree_y + tree_height;
14295
14296   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14297 }
14298
14299 static void
14300 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14301                                       GtkMenu  *menu,
14302                                       gpointer  data)
14303 {
14304   GtkTreeView *tree_view = (GtkTreeView *)data;
14305
14306   tree_view->priv->disable_popdown = 1;
14307   g_signal_connect (menu, "hide",
14308                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14309 }
14310
14311 /* Because we're visible but offscreen, we just set a flag in the preedit
14312  * callback.
14313  */
14314 static void
14315 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14316                                       GtkTreeView  *tree_view)
14317 {
14318   tree_view->priv->imcontext_changed = 1;
14319   if (tree_view->priv->typeselect_flush_timeout)
14320     {
14321       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14322       tree_view->priv->typeselect_flush_timeout =
14323         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14324                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14325                        tree_view);
14326     }
14327
14328 }
14329
14330 static void
14331 gtk_tree_view_search_activate (GtkEntry    *entry,
14332                                GtkTreeView *tree_view)
14333 {
14334   GtkTreePath *path;
14335   GtkRBNode *node;
14336   GtkRBTree *tree;
14337
14338   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14339                                     tree_view,
14340                                     gtk_get_current_event_device ());
14341
14342   /* If we have a row selected and it's the cursor row, we activate
14343    * the row XXX */
14344   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14345     {
14346       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14347       
14348       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14349       
14350       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14351         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14352       
14353       gtk_tree_path_free (path);
14354     }
14355 }
14356
14357 static gboolean
14358 gtk_tree_view_real_search_enable_popdown (gpointer data)
14359 {
14360   GtkTreeView *tree_view = (GtkTreeView *)data;
14361
14362   tree_view->priv->disable_popdown = 0;
14363
14364   return FALSE;
14365 }
14366
14367 static void
14368 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14369                                      gpointer   data)
14370 {
14371   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14372 }
14373
14374 static gboolean
14375 gtk_tree_view_search_delete_event (GtkWidget *widget,
14376                                    GdkEventAny *event,
14377                                    GtkTreeView *tree_view)
14378 {
14379   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14380
14381   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14382
14383   return TRUE;
14384 }
14385
14386 static gboolean
14387 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14388                                          GdkEventButton *event,
14389                                          GtkTreeView *tree_view)
14390 {
14391   GdkDevice *keyb_device;
14392
14393   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14394
14395   keyb_device = gdk_device_get_associated_device (event->device);
14396   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14397
14398   if (event->window == tree_view->priv->bin_window)
14399     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14400
14401   return TRUE;
14402 }
14403
14404 static gboolean
14405 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14406                                    GdkEventScroll *event,
14407                                    GtkTreeView *tree_view)
14408 {
14409   gboolean retval = FALSE;
14410
14411   if (event->direction == GDK_SCROLL_UP)
14412     {
14413       gtk_tree_view_search_move (widget, tree_view, TRUE);
14414       retval = TRUE;
14415     }
14416   else if (event->direction == GDK_SCROLL_DOWN)
14417     {
14418       gtk_tree_view_search_move (widget, tree_view, FALSE);
14419       retval = TRUE;
14420     }
14421
14422   /* renew the flush timeout */
14423   if (retval && tree_view->priv->typeselect_flush_timeout
14424       && !tree_view->priv->search_custom_entry_set)
14425     {
14426       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14427       tree_view->priv->typeselect_flush_timeout =
14428         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14429                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14430                        tree_view);
14431     }
14432
14433   return retval;
14434 }
14435
14436 static gboolean
14437 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14438                                       GdkEventKey *event,
14439                                       GtkTreeView *tree_view)
14440 {
14441   gboolean retval = FALSE;
14442
14443   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14444   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14445
14446   /* close window and cancel the search */
14447   if (!tree_view->priv->search_custom_entry_set
14448       && (event->keyval == GDK_KEY_Escape ||
14449           event->keyval == GDK_KEY_Tab ||
14450             event->keyval == GDK_KEY_KP_Tab ||
14451             event->keyval == GDK_KEY_ISO_Left_Tab))
14452     {
14453       gtk_tree_view_search_dialog_hide (widget, tree_view,
14454                                         gdk_event_get_device ((GdkEvent *) event));
14455       return TRUE;
14456     }
14457
14458   /* select previous matching iter */
14459   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14460     {
14461       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14462         gtk_widget_error_bell (widget);
14463
14464       retval = TRUE;
14465     }
14466
14467   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14468       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14469     {
14470       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14471         gtk_widget_error_bell (widget);
14472
14473       retval = TRUE;
14474     }
14475
14476   /* select next matching iter */
14477   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14478     {
14479       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14480         gtk_widget_error_bell (widget);
14481
14482       retval = TRUE;
14483     }
14484
14485   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14486       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14487     {
14488       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14489         gtk_widget_error_bell (widget);
14490
14491       retval = TRUE;
14492     }
14493
14494   /* renew the flush timeout */
14495   if (retval && tree_view->priv->typeselect_flush_timeout
14496       && !tree_view->priv->search_custom_entry_set)
14497     {
14498       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14499       tree_view->priv->typeselect_flush_timeout =
14500         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14501                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14502                        tree_view);
14503     }
14504
14505   return retval;
14506 }
14507
14508 /*  this function returns FALSE if there is a search string but
14509  *  nothing was found, and TRUE otherwise.
14510  */
14511 static gboolean
14512 gtk_tree_view_search_move (GtkWidget   *window,
14513                            GtkTreeView *tree_view,
14514                            gboolean     up)
14515 {
14516   gboolean ret;
14517   gint len;
14518   gint count = 0;
14519   const gchar *text;
14520   GtkTreeIter iter;
14521   GtkTreeModel *model;
14522   GtkTreeSelection *selection;
14523
14524   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14525
14526   g_return_val_if_fail (text != NULL, FALSE);
14527
14528   len = strlen (text);
14529
14530   if (up && tree_view->priv->selected_iter == 1)
14531     return strlen (text) < 1;
14532
14533   len = strlen (text);
14534
14535   if (len < 1)
14536     return TRUE;
14537
14538   model = gtk_tree_view_get_model (tree_view);
14539   selection = gtk_tree_view_get_selection (tree_view);
14540
14541   /* search */
14542   gtk_tree_selection_unselect_all (selection);
14543   if (!gtk_tree_model_get_iter_first (model, &iter))
14544     return TRUE;
14545
14546   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14547                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14548
14549   if (ret)
14550     {
14551       /* found */
14552       tree_view->priv->selected_iter += up?(-1):(1);
14553       return TRUE;
14554     }
14555   else
14556     {
14557       /* return to old iter */
14558       count = 0;
14559       gtk_tree_model_get_iter_first (model, &iter);
14560       gtk_tree_view_search_iter (model, selection,
14561                                  &iter, text,
14562                                  &count, tree_view->priv->selected_iter);
14563       return FALSE;
14564     }
14565 }
14566
14567 static gboolean
14568 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14569                                  gint          column,
14570                                  const gchar  *key,
14571                                  GtkTreeIter  *iter,
14572                                  gpointer      search_data)
14573 {
14574   gboolean retval = TRUE;
14575   const gchar *str;
14576   gchar *normalized_string;
14577   gchar *normalized_key;
14578   gchar *case_normalized_string = NULL;
14579   gchar *case_normalized_key = NULL;
14580   GValue value = {0,};
14581   GValue transformed = {0,};
14582
14583   gtk_tree_model_get_value (model, iter, column, &value);
14584
14585   g_value_init (&transformed, G_TYPE_STRING);
14586
14587   if (!g_value_transform (&value, &transformed))
14588     {
14589       g_value_unset (&value);
14590       return TRUE;
14591     }
14592
14593   g_value_unset (&value);
14594
14595   str = g_value_get_string (&transformed);
14596   if (!str)
14597     {
14598       g_value_unset (&transformed);
14599       return TRUE;
14600     }
14601
14602   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14603   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14604
14605   if (normalized_string && normalized_key)
14606     {
14607       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14608       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14609
14610       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14611         retval = FALSE;
14612     }
14613
14614   g_value_unset (&transformed);
14615   g_free (normalized_key);
14616   g_free (normalized_string);
14617   g_free (case_normalized_key);
14618   g_free (case_normalized_string);
14619
14620   return retval;
14621 }
14622
14623 static gboolean
14624 gtk_tree_view_search_iter (GtkTreeModel     *model,
14625                            GtkTreeSelection *selection,
14626                            GtkTreeIter      *iter,
14627                            const gchar      *text,
14628                            gint             *count,
14629                            gint              n)
14630 {
14631   GtkRBTree *tree = NULL;
14632   GtkRBNode *node = NULL;
14633   GtkTreePath *path;
14634
14635   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14636
14637   path = gtk_tree_model_get_path (model, iter);
14638   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14639
14640   do
14641     {
14642       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14643         {
14644           (*count)++;
14645           if (*count == n)
14646             {
14647               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14648                                             TRUE, 0.5, 0.0);
14649               gtk_tree_selection_select_iter (selection, iter);
14650               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14651
14652               if (path)
14653                 gtk_tree_path_free (path);
14654
14655               return TRUE;
14656             }
14657         }
14658
14659       if (node->children)
14660         {
14661           gboolean has_child;
14662           GtkTreeIter tmp;
14663
14664           tree = node->children;
14665           node = tree->root;
14666
14667           while (node->left != tree->nil)
14668             node = node->left;
14669
14670           tmp = *iter;
14671           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14672           gtk_tree_path_down (path);
14673
14674           /* sanity check */
14675           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14676         }
14677       else
14678         {
14679           gboolean done = FALSE;
14680
14681           do
14682             {
14683               node = _gtk_rbtree_next (tree, node);
14684
14685               if (node)
14686                 {
14687                   gboolean has_next;
14688
14689                   has_next = gtk_tree_model_iter_next (model, iter);
14690
14691                   done = TRUE;
14692                   gtk_tree_path_next (path);
14693
14694                   /* sanity check */
14695                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14696                 }
14697               else
14698                 {
14699                   gboolean has_parent;
14700                   GtkTreeIter tmp_iter = *iter;
14701
14702                   node = tree->parent_node;
14703                   tree = tree->parent_tree;
14704
14705                   if (!tree)
14706                     {
14707                       if (path)
14708                         gtk_tree_path_free (path);
14709
14710                       /* we've run out of tree, done with this func */
14711                       return FALSE;
14712                     }
14713
14714                   has_parent = gtk_tree_model_iter_parent (model,
14715                                                            iter,
14716                                                            &tmp_iter);
14717                   gtk_tree_path_up (path);
14718
14719                   /* sanity check */
14720                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14721                 }
14722             }
14723           while (!done);
14724         }
14725     }
14726   while (1);
14727
14728   return FALSE;
14729 }
14730
14731 static void
14732 gtk_tree_view_search_init (GtkWidget   *entry,
14733                            GtkTreeView *tree_view)
14734 {
14735   gint ret;
14736   gint count = 0;
14737   const gchar *text;
14738   GtkTreeIter iter;
14739   GtkTreeModel *model;
14740   GtkTreeSelection *selection;
14741
14742   g_return_if_fail (GTK_IS_ENTRY (entry));
14743   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14744
14745   text = gtk_entry_get_text (GTK_ENTRY (entry));
14746
14747   model = gtk_tree_view_get_model (tree_view);
14748   selection = gtk_tree_view_get_selection (tree_view);
14749
14750   /* search */
14751   gtk_tree_selection_unselect_all (selection);
14752   if (tree_view->priv->typeselect_flush_timeout
14753       && !tree_view->priv->search_custom_entry_set)
14754     {
14755       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14756       tree_view->priv->typeselect_flush_timeout =
14757         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14758                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14759                        tree_view);
14760     }
14761
14762   if (*text == '\0')
14763     return;
14764
14765   if (!gtk_tree_model_get_iter_first (model, &iter))
14766     return;
14767
14768   ret = gtk_tree_view_search_iter (model, selection,
14769                                    &iter, text,
14770                                    &count, 1);
14771
14772   if (ret)
14773     tree_view->priv->selected_iter = 1;
14774 }
14775
14776 static void
14777 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14778                              GtkTreeView     *tree_view)
14779 {
14780   if (tree_view->priv->edited_column == NULL)
14781     return;
14782
14783   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14784   tree_view->priv->edited_column = NULL;
14785
14786   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14787     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14788
14789   g_signal_handlers_disconnect_by_func (cell_editable,
14790                                         gtk_tree_view_remove_widget,
14791                                         tree_view);
14792
14793   gtk_container_remove (GTK_CONTAINER (tree_view),
14794                         GTK_WIDGET (cell_editable));  
14795
14796   /* FIXME should only redraw a single node */
14797   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14798 }
14799
14800 static gboolean
14801 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14802                              GtkTreePath *cursor_path)
14803 {
14804   GtkTreeIter iter;
14805   GdkRectangle background_area;
14806   GdkRectangle cell_area;
14807   GtkCellEditable *editable_widget = NULL;
14808   gchar *path_string;
14809   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14810   gint retval = FALSE;
14811   GtkRBTree *cursor_tree;
14812   GtkRBNode *cursor_node;
14813
14814   g_assert (tree_view->priv->focus_column);
14815
14816   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14817     return FALSE;
14818
14819   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14820       cursor_node == NULL)
14821     return FALSE;
14822
14823   path_string = gtk_tree_path_to_string (cursor_path);
14824   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14825
14826   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14827
14828   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14829                                            tree_view->priv->model,
14830                                            &iter,
14831                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14832                                            cursor_node->children?TRUE:FALSE);
14833   gtk_tree_view_get_background_area (tree_view,
14834                                      cursor_path,
14835                                      tree_view->priv->focus_column,
14836                                      &background_area);
14837   gtk_tree_view_get_cell_area (tree_view,
14838                                cursor_path,
14839                                tree_view->priv->focus_column,
14840                                &cell_area);
14841
14842   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14843                                         &editable_widget,
14844                                         NULL,
14845                                         path_string,
14846                                         &background_area,
14847                                         &cell_area,
14848                                         flags))
14849     {
14850       retval = TRUE;
14851       if (editable_widget != NULL)
14852         {
14853           gint left, right;
14854           GdkRectangle area;
14855           GtkCellRenderer *cell;
14856
14857           area = cell_area;
14858           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14859
14860           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14861
14862           area.x += left;
14863           area.width -= right + left;
14864
14865           gtk_tree_view_real_start_editing (tree_view,
14866                                             tree_view->priv->focus_column,
14867                                             cursor_path,
14868                                             editable_widget,
14869                                             &area,
14870                                             NULL,
14871                                             flags);
14872         }
14873
14874     }
14875   g_free (path_string);
14876   return retval;
14877 }
14878
14879 static void
14880 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14881                                   GtkTreeViewColumn *column,
14882                                   GtkTreePath       *path,
14883                                   GtkCellEditable   *cell_editable,
14884                                   GdkRectangle      *cell_area,
14885                                   GdkEvent          *event,
14886                                   guint              flags)
14887 {
14888   gint pre_val = tree_view->priv->vadjustment->value;
14889   GtkRequisition requisition;
14890
14891   tree_view->priv->edited_column = column;
14892   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14893
14894   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14895   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14896
14897   gtk_size_request_get_size (GTK_SIZE_REQUEST (cell_editable),
14898                              &requisition, NULL);
14899
14900   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14901
14902   if (requisition.height < cell_area->height)
14903     {
14904       gint diff = cell_area->height - requisition.height;
14905       gtk_tree_view_put (tree_view,
14906                          GTK_WIDGET (cell_editable),
14907                          cell_area->x, cell_area->y + diff/2,
14908                          cell_area->width, requisition.height);
14909     }
14910   else
14911     {
14912       gtk_tree_view_put (tree_view,
14913                          GTK_WIDGET (cell_editable),
14914                          cell_area->x, cell_area->y,
14915                          cell_area->width, cell_area->height);
14916     }
14917
14918   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14919                                    (GdkEvent *)event);
14920
14921   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14922   g_signal_connect (cell_editable, "remove-widget",
14923                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14924 }
14925
14926 static void
14927 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14928                             gboolean     cancel_editing)
14929 {
14930   GtkTreeViewColumn *column;
14931   GtkCellRenderer *cell;
14932
14933   if (tree_view->priv->edited_column == NULL)
14934     return;
14935
14936   /*
14937    * This is very evil. We need to do this, because
14938    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14939    * later on. If gtk_tree_view_row_changed notices
14940    * tree_view->priv->edited_column != NULL, it'll call
14941    * gtk_tree_view_stop_editing again. Bad things will happen then.
14942    *
14943    * Please read that again if you intend to modify anything here.
14944    */
14945
14946   column = tree_view->priv->edited_column;
14947   tree_view->priv->edited_column = NULL;
14948
14949   cell = _gtk_tree_view_column_get_edited_cell (column);
14950   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14951
14952   if (!cancel_editing)
14953     gtk_cell_editable_editing_done (column->editable_widget);
14954
14955   tree_view->priv->edited_column = column;
14956
14957   gtk_cell_editable_remove_widget (column->editable_widget);
14958 }
14959
14960
14961 /**
14962  * gtk_tree_view_set_hover_selection:
14963  * @tree_view: a #GtkTreeView
14964  * @hover: %TRUE to enable hover selection mode
14965  *
14966  * Enables of disables the hover selection mode of @tree_view.
14967  * Hover selection makes the selected row follow the pointer.
14968  * Currently, this works only for the selection modes 
14969  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14970  * 
14971  * Since: 2.6
14972  **/
14973 void     
14974 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14975                                    gboolean     hover)
14976 {
14977   hover = hover != FALSE;
14978
14979   if (hover != tree_view->priv->hover_selection)
14980     {
14981       tree_view->priv->hover_selection = hover;
14982
14983       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14984     }
14985 }
14986
14987 /**
14988  * gtk_tree_view_get_hover_selection:
14989  * @tree_view: a #GtkTreeView
14990  * 
14991  * Returns whether hover selection mode is turned on for @tree_view.
14992  * 
14993  * Return value: %TRUE if @tree_view is in hover selection mode
14994  *
14995  * Since: 2.6 
14996  **/
14997 gboolean 
14998 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14999 {
15000   return tree_view->priv->hover_selection;
15001 }
15002
15003 /**
15004  * gtk_tree_view_set_hover_expand:
15005  * @tree_view: a #GtkTreeView
15006  * @expand: %TRUE to enable hover selection mode
15007  *
15008  * Enables of disables the hover expansion mode of @tree_view.
15009  * Hover expansion makes rows expand or collapse if the pointer 
15010  * moves over them.
15011  * 
15012  * Since: 2.6
15013  **/
15014 void     
15015 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15016                                 gboolean     expand)
15017 {
15018   expand = expand != FALSE;
15019
15020   if (expand != tree_view->priv->hover_expand)
15021     {
15022       tree_view->priv->hover_expand = expand;
15023
15024       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15025     }
15026 }
15027
15028 /**
15029  * gtk_tree_view_get_hover_expand:
15030  * @tree_view: a #GtkTreeView
15031  * 
15032  * Returns whether hover expansion mode is turned on for @tree_view.
15033  * 
15034  * Return value: %TRUE if @tree_view is in hover expansion mode
15035  *
15036  * Since: 2.6 
15037  **/
15038 gboolean 
15039 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15040 {
15041   return tree_view->priv->hover_expand;
15042 }
15043
15044 /**
15045  * gtk_tree_view_set_rubber_banding:
15046  * @tree_view: a #GtkTreeView
15047  * @enable: %TRUE to enable rubber banding
15048  *
15049  * Enables or disables rubber banding in @tree_view.  If the selection mode
15050  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15051  * multiple rows by dragging the mouse.
15052  * 
15053  * Since: 2.10
15054  **/
15055 void
15056 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15057                                   gboolean     enable)
15058 {
15059   enable = enable != FALSE;
15060
15061   if (enable != tree_view->priv->rubber_banding_enable)
15062     {
15063       tree_view->priv->rubber_banding_enable = enable;
15064
15065       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15066     }
15067 }
15068
15069 /**
15070  * gtk_tree_view_get_rubber_banding:
15071  * @tree_view: a #GtkTreeView
15072  * 
15073  * Returns whether rubber banding is turned on for @tree_view.  If the
15074  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15075  * user to select multiple rows by dragging the mouse.
15076  * 
15077  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15078  *
15079  * Since: 2.10
15080  **/
15081 gboolean
15082 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15083 {
15084   return tree_view->priv->rubber_banding_enable;
15085 }
15086
15087 /**
15088  * gtk_tree_view_is_rubber_banding_active:
15089  * @tree_view: a #GtkTreeView
15090  * 
15091  * Returns whether a rubber banding operation is currently being done
15092  * in @tree_view.
15093  *
15094  * Return value: %TRUE if a rubber banding operation is currently being
15095  * done in @tree_view.
15096  *
15097  * Since: 2.12
15098  **/
15099 gboolean
15100 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15101 {
15102   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15103
15104   if (tree_view->priv->rubber_banding_enable
15105       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15106     return TRUE;
15107
15108   return FALSE;
15109 }
15110
15111 /**
15112  * gtk_tree_view_get_row_separator_func:
15113  * @tree_view: a #GtkTreeView
15114  * 
15115  * Returns the current row separator function.
15116  * 
15117  * Return value: the current row separator function.
15118  *
15119  * Since: 2.6
15120  **/
15121 GtkTreeViewRowSeparatorFunc 
15122 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15123 {
15124   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15125
15126   return tree_view->priv->row_separator_func;
15127 }
15128
15129 /**
15130  * gtk_tree_view_set_row_separator_func:
15131  * @tree_view: a #GtkTreeView
15132  * @func: a #GtkTreeViewRowSeparatorFunc
15133  * @data: (allow-none): user data to pass to @func, or %NULL
15134  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15135  * 
15136  * Sets the row separator function, which is used to determine
15137  * whether a row should be drawn as a separator. If the row separator
15138  * function is %NULL, no separators are drawn. This is the default value.
15139  *
15140  * Since: 2.6
15141  **/
15142 void
15143 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15144                                       GtkTreeViewRowSeparatorFunc  func,
15145                                       gpointer                     data,
15146                                       GDestroyNotify               destroy)
15147 {
15148   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15149
15150   if (tree_view->priv->row_separator_destroy)
15151     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15152
15153   tree_view->priv->row_separator_func = func;
15154   tree_view->priv->row_separator_data = data;
15155   tree_view->priv->row_separator_destroy = destroy;
15156
15157   /* Have the tree recalculate heights */
15158   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15159   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15160 }
15161
15162   
15163 static void
15164 gtk_tree_view_grab_notify (GtkWidget *widget,
15165                            gboolean   was_grabbed)
15166 {
15167   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15168
15169   tree_view->priv->in_grab = !was_grabbed;
15170
15171   if (!was_grabbed)
15172     {
15173       tree_view->priv->pressed_button = -1;
15174
15175       if (tree_view->priv->rubber_band_status)
15176         gtk_tree_view_stop_rubber_band (tree_view);
15177     }
15178 }
15179
15180 static void
15181 gtk_tree_view_state_changed (GtkWidget      *widget,
15182                              GtkStateType    previous_state)
15183 {
15184   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15185
15186   if (gtk_widget_get_realized (widget))
15187     {
15188       gdk_window_set_back_pixmap (gtk_widget_get_window (widget), NULL, FALSE);
15189       gdk_window_set_background (tree_view->priv->bin_window,
15190                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15191     }
15192
15193   gtk_widget_queue_draw (widget);
15194 }
15195
15196 /**
15197  * gtk_tree_view_get_grid_lines:
15198  * @tree_view: a #GtkTreeView
15199  *
15200  * Returns which grid lines are enabled in @tree_view.
15201  *
15202  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15203  * are enabled.
15204  *
15205  * Since: 2.10
15206  */
15207 GtkTreeViewGridLines
15208 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15209 {
15210   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15211
15212   return tree_view->priv->grid_lines;
15213 }
15214
15215 /**
15216  * gtk_tree_view_set_grid_lines:
15217  * @tree_view: a #GtkTreeView
15218  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15219  * enable.
15220  *
15221  * Sets which grid lines to draw in @tree_view.
15222  *
15223  * Since: 2.10
15224  */
15225 void
15226 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15227                               GtkTreeViewGridLines   grid_lines)
15228 {
15229   GtkTreeViewPrivate *priv;
15230   GtkWidget *widget;
15231   GtkTreeViewGridLines old_grid_lines;
15232
15233   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15234
15235   priv = tree_view->priv;
15236   widget = GTK_WIDGET (tree_view);
15237
15238   old_grid_lines = priv->grid_lines;
15239   priv->grid_lines = grid_lines;
15240   
15241   if (gtk_widget_get_realized (widget))
15242     {
15243       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15244           priv->grid_line_width)
15245         {
15246           priv->grid_line_width = 0;
15247         }
15248       
15249       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15250           !priv->grid_line_width)
15251         {
15252           gint8 *dash_list;
15253
15254           gtk_widget_style_get (widget,
15255                                 "grid-line-width", &priv->grid_line_width,
15256                                 "grid-line-pattern", (gchar *)&dash_list,
15257                                 NULL);
15258       
15259           if (dash_list)
15260             {
15261               priv->grid_line_dashes[0] = dash_list[0];
15262               if (dash_list[0])
15263                 priv->grid_line_dashes[1] = dash_list[1];
15264               
15265               g_free (dash_list);
15266             }
15267           else
15268             {
15269               priv->grid_line_dashes[0] = 1;
15270               priv->grid_line_dashes[1] = 1;
15271             }
15272         }      
15273     }
15274
15275   if (old_grid_lines != grid_lines)
15276     {
15277       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15278       
15279       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15280     }
15281 }
15282
15283 /**
15284  * gtk_tree_view_get_enable_tree_lines:
15285  * @tree_view: a #GtkTreeView.
15286  *
15287  * Returns whether or not tree lines are drawn in @tree_view.
15288  *
15289  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15290  * otherwise.
15291  *
15292  * Since: 2.10
15293  */
15294 gboolean
15295 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15296 {
15297   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15298
15299   return tree_view->priv->tree_lines_enabled;
15300 }
15301
15302 /**
15303  * gtk_tree_view_set_enable_tree_lines:
15304  * @tree_view: a #GtkTreeView
15305  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15306  *
15307  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15308  * This does not have any visible effects for lists.
15309  *
15310  * Since: 2.10
15311  */
15312 void
15313 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15314                                      gboolean     enabled)
15315 {
15316   GtkTreeViewPrivate *priv;
15317   GtkWidget *widget;
15318   gboolean was_enabled;
15319
15320   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15321
15322   enabled = enabled != FALSE;
15323
15324   priv = tree_view->priv;
15325   widget = GTK_WIDGET (tree_view);
15326
15327   was_enabled = priv->tree_lines_enabled;
15328
15329   priv->tree_lines_enabled = enabled;
15330
15331   if (gtk_widget_get_realized (widget))
15332     {
15333       if (!enabled && priv->tree_line_width)
15334         {
15335           priv->tree_line_width = 0;
15336         }
15337       
15338       if (enabled && !priv->tree_line_width)
15339         {
15340           gint8 *dash_list;
15341           gtk_widget_style_get (widget,
15342                                 "tree-line-width", &priv->tree_line_width,
15343                                 "tree-line-pattern", (gchar *)&dash_list,
15344                                 NULL);
15345           
15346           if (dash_list)
15347             {
15348               priv->tree_line_dashes[0] = dash_list[0];
15349               if (dash_list[0])
15350                 priv->tree_line_dashes[1] = dash_list[1];
15351               
15352               g_free (dash_list);
15353             }
15354           else
15355             {
15356               priv->tree_line_dashes[0] = 1;
15357               priv->tree_line_dashes[1] = 1;
15358             }
15359         }
15360     }
15361
15362   if (was_enabled != enabled)
15363     {
15364       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15365
15366       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15367     }
15368 }
15369
15370
15371 /**
15372  * gtk_tree_view_set_show_expanders:
15373  * @tree_view: a #GtkTreeView
15374  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15375  *
15376  * Sets whether to draw and enable expanders and indent child rows in
15377  * @tree_view.  When disabled there will be no expanders visible in trees
15378  * and there will be no way to expand and collapse rows by default.  Also
15379  * note that hiding the expanders will disable the default indentation.  You
15380  * can set a custom indentation in this case using
15381  * gtk_tree_view_set_level_indentation().
15382  * This does not have any visible effects for lists.
15383  *
15384  * Since: 2.12
15385  */
15386 void
15387 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15388                                   gboolean     enabled)
15389 {
15390   gboolean was_enabled;
15391
15392   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15393
15394   enabled = enabled != FALSE;
15395   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15396
15397   if (enabled)
15398     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15399   else
15400     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15401
15402   if (enabled != was_enabled)
15403     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15404 }
15405
15406 /**
15407  * gtk_tree_view_get_show_expanders:
15408  * @tree_view: a #GtkTreeView.
15409  *
15410  * Returns whether or not expanders are drawn in @tree_view.
15411  *
15412  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15413  * otherwise.
15414  *
15415  * Since: 2.12
15416  */
15417 gboolean
15418 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15419 {
15420   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15421
15422   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15423 }
15424
15425 /**
15426  * gtk_tree_view_set_level_indentation:
15427  * @tree_view: a #GtkTreeView
15428  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15429  *
15430  * Sets the amount of extra indentation for child levels to use in @tree_view
15431  * in addition to the default indentation.  The value should be specified in
15432  * pixels, a value of 0 disables this feature and in this case only the default
15433  * indentation will be used.
15434  * This does not have any visible effects for lists.
15435  *
15436  * Since: 2.12
15437  */
15438 void
15439 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15440                                      gint         indentation)
15441 {
15442   tree_view->priv->level_indentation = indentation;
15443
15444   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15445 }
15446
15447 /**
15448  * gtk_tree_view_get_level_indentation:
15449  * @tree_view: a #GtkTreeView.
15450  *
15451  * Returns the amount, in pixels, of extra indentation for child levels
15452  * in @tree_view.
15453  *
15454  * Return value: the amount of extra indentation for child levels in
15455  * @tree_view.  A return value of 0 means that this feature is disabled.
15456  *
15457  * Since: 2.12
15458  */
15459 gint
15460 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15461 {
15462   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15463
15464   return tree_view->priv->level_indentation;
15465 }
15466
15467 /**
15468  * gtk_tree_view_set_tooltip_row:
15469  * @tree_view: a #GtkTreeView
15470  * @tooltip: a #GtkTooltip
15471  * @path: a #GtkTreePath
15472  *
15473  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15474  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15475  * See also gtk_tooltip_set_tip_area().
15476  *
15477  * Since: 2.12
15478  */
15479 void
15480 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15481                                GtkTooltip  *tooltip,
15482                                GtkTreePath *path)
15483 {
15484   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15485   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15486
15487   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15488 }
15489
15490 /**
15491  * gtk_tree_view_set_tooltip_cell:
15492  * @tree_view: a #GtkTreeView
15493  * @tooltip: a #GtkTooltip
15494  * @path: (allow-none): a #GtkTreePath or %NULL
15495  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15496  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15497  *
15498  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15499  * in common.  For example if @path is %NULL and @column is set, the tip
15500  * area will be set to the full area covered by @column.  See also
15501  * gtk_tooltip_set_tip_area().
15502  *
15503  * Note that if @path is not specified and @cell is set and part of a column
15504  * containing the expander, the tooltip might not show and hide at the correct
15505  * position.  In such cases @path must be set to the current node under the
15506  * mouse cursor for this function to operate correctly.
15507  *
15508  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15509  *
15510  * Since: 2.12
15511  */
15512 void
15513 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15514                                 GtkTooltip        *tooltip,
15515                                 GtkTreePath       *path,
15516                                 GtkTreeViewColumn *column,
15517                                 GtkCellRenderer   *cell)
15518 {
15519   GtkAllocation allocation;
15520   GdkRectangle rect;
15521
15522   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15523   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15524   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15525   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15526
15527   /* Determine x values. */
15528   if (column && cell)
15529     {
15530       GdkRectangle tmp;
15531       gint start, width;
15532
15533       /* We always pass in path here, whether it is NULL or not.
15534        * For cells in expander columns path must be specified so that
15535        * we can correctly account for the indentation.  This also means
15536        * that the tooltip is constrained vertically by the "Determine y
15537        * values" code below; this is not a real problem since cells actually
15538        * don't stretch vertically in constrast to columns.
15539        */
15540       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15541       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15542
15543       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15544                                                          tmp.x + start, 0,
15545                                                          &rect.x, NULL);
15546       rect.width = width;
15547     }
15548   else if (column)
15549     {
15550       GdkRectangle tmp;
15551
15552       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15553       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15554                                                          tmp.x, 0,
15555                                                          &rect.x, NULL);
15556       rect.width = tmp.width;
15557     }
15558   else
15559     {
15560       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15561       rect.x = 0;
15562       rect.width = allocation.width;
15563     }
15564
15565   /* Determine y values. */
15566   if (path)
15567     {
15568       GdkRectangle tmp;
15569
15570       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15571       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15572                                                          0, tmp.y,
15573                                                          NULL, &rect.y);
15574       rect.height = tmp.height;
15575     }
15576   else
15577     {
15578       rect.y = 0;
15579       rect.height = tree_view->priv->vadjustment->page_size;
15580     }
15581
15582   gtk_tooltip_set_tip_area (tooltip, &rect);
15583 }
15584
15585 /**
15586  * gtk_tree_view_get_tooltip_context:
15587  * @tree_view: a #GtkTreeView
15588  * @x: the x coordinate (relative to widget coordinates)
15589  * @y: the y coordinate (relative to widget coordinates)
15590  * @keyboard_tip: whether this is a keyboard tooltip or not
15591  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15592  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15593  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15594  *
15595  * This function is supposed to be used in a #GtkWidget::query-tooltip
15596  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15597  * which are received in the signal handler, should be passed to this
15598  * function without modification.
15599  *
15600  * The return value indicates whether there is a tree view row at the given
15601  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15602  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15603  * @model, @path and @iter which have been provided will be set to point to
15604  * that row and the corresponding model.  @x and @y will always be converted
15605  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15606  *
15607  * Return value: whether or not the given tooltip context points to a row.
15608  *
15609  * Since: 2.12
15610  */
15611 gboolean
15612 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15613                                    gint          *x,
15614                                    gint          *y,
15615                                    gboolean       keyboard_tip,
15616                                    GtkTreeModel **model,
15617                                    GtkTreePath  **path,
15618                                    GtkTreeIter   *iter)
15619 {
15620   GtkTreePath *tmppath = NULL;
15621
15622   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15623   g_return_val_if_fail (x != NULL, FALSE);
15624   g_return_val_if_fail (y != NULL, FALSE);
15625
15626   if (keyboard_tip)
15627     {
15628       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15629
15630       if (!tmppath)
15631         return FALSE;
15632     }
15633   else
15634     {
15635       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15636                                                          x, y);
15637
15638       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15639                                           &tmppath, NULL, NULL, NULL))
15640         return FALSE;
15641     }
15642
15643   if (model)
15644     *model = gtk_tree_view_get_model (tree_view);
15645
15646   if (iter)
15647     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15648                              iter, tmppath);
15649
15650   if (path)
15651     *path = tmppath;
15652   else
15653     gtk_tree_path_free (tmppath);
15654
15655   return TRUE;
15656 }
15657
15658 static gboolean
15659 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15660                                     gint        x,
15661                                     gint        y,
15662                                     gboolean    keyboard_tip,
15663                                     GtkTooltip *tooltip,
15664                                     gpointer    data)
15665 {
15666   GValue value = { 0, };
15667   GValue transformed = { 0, };
15668   GtkTreeIter iter;
15669   GtkTreePath *path;
15670   GtkTreeModel *model;
15671   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15672
15673   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15674                                           &x, &y,
15675                                           keyboard_tip,
15676                                           &model, &path, &iter))
15677     return FALSE;
15678
15679   gtk_tree_model_get_value (model, &iter,
15680                             tree_view->priv->tooltip_column, &value);
15681
15682   g_value_init (&transformed, G_TYPE_STRING);
15683
15684   if (!g_value_transform (&value, &transformed))
15685     {
15686       g_value_unset (&value);
15687       gtk_tree_path_free (path);
15688
15689       return FALSE;
15690     }
15691
15692   g_value_unset (&value);
15693
15694   if (!g_value_get_string (&transformed))
15695     {
15696       g_value_unset (&transformed);
15697       gtk_tree_path_free (path);
15698
15699       return FALSE;
15700     }
15701
15702   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15703   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15704
15705   gtk_tree_path_free (path);
15706   g_value_unset (&transformed);
15707
15708   return TRUE;
15709 }
15710
15711 /**
15712  * gtk_tree_view_set_tooltip_column:
15713  * @tree_view: a #GtkTreeView
15714  * @column: an integer, which is a valid column number for @tree_view's model
15715  *
15716  * If you only plan to have simple (text-only) tooltips on full rows, you
15717  * can use this function to have #GtkTreeView handle these automatically
15718  * for you. @column should be set to the column in @tree_view's model
15719  * containing the tooltip texts, or -1 to disable this feature.
15720  *
15721  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15722  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15723  *
15724  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15725  * so &amp;, &lt;, etc have to be escaped in the text.
15726  *
15727  * Since: 2.12
15728  */
15729 void
15730 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15731                                   gint         column)
15732 {
15733   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15734
15735   if (column == tree_view->priv->tooltip_column)
15736     return;
15737
15738   if (column == -1)
15739     {
15740       g_signal_handlers_disconnect_by_func (tree_view,
15741                                             gtk_tree_view_set_tooltip_query_cb,
15742                                             NULL);
15743       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15744     }
15745   else
15746     {
15747       if (tree_view->priv->tooltip_column == -1)
15748         {
15749           g_signal_connect (tree_view, "query-tooltip",
15750                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15751           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15752         }
15753     }
15754
15755   tree_view->priv->tooltip_column = column;
15756   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15757 }
15758
15759 /**
15760  * gtk_tree_view_get_tooltip_column:
15761  * @tree_view: a #GtkTreeView
15762  *
15763  * Returns the column of @tree_view's model which is being used for
15764  * displaying tooltips on @tree_view's rows.
15765  *
15766  * Return value: the index of the tooltip column that is currently being
15767  * used, or -1 if this is disabled.
15768  *
15769  * Since: 2.12
15770  */
15771 gint
15772 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15773 {
15774   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15775
15776   return tree_view->priv->tooltip_column;
15777 }