]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Update to explain the situation.
[~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 "gtkprivate.h"
47 #include "gtkalias.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_NUM_ROWS_PER_IDLE 500
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 gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView        *tree_view,
349                                                               GtkTreeIter        *iter,
350                                                               gint                depth,
351                                                               gint               *height,
352                                                               GtkRBNode          *node);
353 static void     gtk_tree_view_discover_dirty                 (GtkTreeView        *tree_view,
354                                                               GtkRBTree          *tree,
355                                                               GtkTreeIter        *iter,
356                                                               gint                depth);
357 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
358                                                               GtkRBTree          *tree,
359                                                               GtkRBNode          *node);
360 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
361                                                               GtkTreeViewColumn  *column,
362                                                               gboolean            focus_to_cell);
363 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
364                                                               GdkEventMotion     *event);
365 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
366 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
367                                                               gint                count);
368 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
369                                                               gint                count);
370 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
371                                                               gint                count);
372 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
373                                                               gint                count);
374 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
375                                                               GtkTreePath        *path,
376                                                               GtkRBTree          *tree,
377                                                               GtkRBNode          *node,
378                                                               gboolean            animate);
379 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
380                                                               GtkTreePath        *path,
381                                                               GtkRBTree          *tree,
382                                                               GtkRBNode          *node,
383                                                               gboolean            open_all,
384                                                               gboolean            animate);
385 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
386                                                               GtkTreePath        *path,
387                                                               gboolean            clear_and_select,
388                                                               gboolean            clamp_node);
389 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
390 static void     column_sizing_notify                         (GObject            *object,
391                                                               GParamSpec         *pspec,
392                                                               gpointer            data);
393 static gboolean expand_collapse_timeout                      (gpointer            data);
394 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
395                                                               GtkRBTree          *tree,
396                                                               GtkRBNode          *node,
397                                                               gboolean            expand);
398 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
399 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
400 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
401 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
402
403 /* interactive search */
404 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
405 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
406                                                          GtkTreeView      *tree_view);
407 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
408                                                          GtkWidget        *search_dialog,
409                                                          gpointer          user_data);
410 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
411                                                          GtkMenu          *menu,
412                                                          gpointer          data);
413 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
414                                                          GtkTreeView      *tree_view);
415 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
418 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
419                                                          gpointer          data);
420 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
421                                                          GdkEventAny      *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
424                                                          GdkEventButton   *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
427                                                          GdkEventScroll   *event,
428                                                          GtkTreeView      *tree_view);
429 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
430                                                          GdkEventKey      *event,
431                                                          GtkTreeView      *tree_view);
432 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
433                                                          GtkTreeView      *tree_view,
434                                                          gboolean          up);
435 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
436                                                          gint              column,
437                                                          const gchar      *key,
438                                                          GtkTreeIter      *iter,
439                                                          gpointer          search_data);
440 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
441                                                          GtkTreeSelection *selection,
442                                                          GtkTreeIter      *iter,
443                                                          const gchar      *text,
444                                                          gint             *count,
445                                                          gint              n);
446 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
447                                                          GtkTreeView      *tree_view);
448 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
449                                                          GtkWidget        *child_widget,
450                                                          gint              x,
451                                                          gint              y,
452                                                          gint              width,
453                                                          gint              height);
454 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
455                                                          GtkTreePath      *cursor_path);
456 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
457                                               GtkTreeViewColumn *column,
458                                               GtkTreePath       *path,
459                                               GtkCellEditable   *cell_editable,
460                                               GdkRectangle      *cell_area,
461                                               GdkEvent          *event,
462                                               guint              flags);
463 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
464                                                          gboolean     cancel_editing);
465 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
466                                                              gboolean     keybinding);
467 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
468 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
469                                                          GtkTreeViewColumn *column,
470                                                          gint               drop_position);
471
472 /* GtkBuildable */
473 static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
474                                                GtkBuilder  *builder,
475                                                GObject     *child,
476                                                const gchar *type);
477 static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
478
479
480 static gboolean scroll_row_timeout                   (gpointer     data);
481 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
482 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
483
484 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
485
486 \f
487
488 /* GType Methods
489  */
490
491 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
492                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
493                                                 gtk_tree_view_buildable_init))
494
495 static void
496 gtk_tree_view_class_init (GtkTreeViewClass *class)
497 {
498   GObjectClass *o_class;
499   GtkObjectClass *object_class;
500   GtkWidgetClass *widget_class;
501   GtkContainerClass *container_class;
502   GtkBindingSet *binding_set;
503
504   binding_set = gtk_binding_set_by_class (class);
505
506   o_class = (GObjectClass *) class;
507   object_class = (GtkObjectClass *) class;
508   widget_class = (GtkWidgetClass *) class;
509   container_class = (GtkContainerClass *) class;
510
511   /* GObject signals */
512   o_class->set_property = gtk_tree_view_set_property;
513   o_class->get_property = gtk_tree_view_get_property;
514   o_class->finalize = gtk_tree_view_finalize;
515
516   /* GtkObject signals */
517   object_class->destroy = gtk_tree_view_destroy;
518
519   /* GtkWidget signals */
520   widget_class->map = gtk_tree_view_map;
521   widget_class->realize = gtk_tree_view_realize;
522   widget_class->unrealize = gtk_tree_view_unrealize;
523   widget_class->size_request = gtk_tree_view_size_request;
524   widget_class->size_allocate = gtk_tree_view_size_allocate;
525   widget_class->button_press_event = gtk_tree_view_button_press;
526   widget_class->button_release_event = gtk_tree_view_button_release;
527   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
528   /*widget_class->configure_event = gtk_tree_view_configure;*/
529   widget_class->motion_notify_event = gtk_tree_view_motion;
530   widget_class->expose_event = gtk_tree_view_expose;
531   widget_class->key_press_event = gtk_tree_view_key_press;
532   widget_class->key_release_event = gtk_tree_view_key_release;
533   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
534   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
535   widget_class->focus_out_event = gtk_tree_view_focus_out;
536   widget_class->drag_begin = gtk_tree_view_drag_begin;
537   widget_class->drag_end = gtk_tree_view_drag_end;
538   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
539   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
540   widget_class->drag_leave = gtk_tree_view_drag_leave;
541   widget_class->drag_motion = gtk_tree_view_drag_motion;
542   widget_class->drag_drop = gtk_tree_view_drag_drop;
543   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
544   widget_class->focus = gtk_tree_view_focus;
545   widget_class->grab_focus = gtk_tree_view_grab_focus;
546   widget_class->style_set = gtk_tree_view_style_set;
547   widget_class->grab_notify = gtk_tree_view_grab_notify;
548   widget_class->state_changed = gtk_tree_view_state_changed;
549
550   /* GtkContainer signals */
551   container_class->remove = gtk_tree_view_remove;
552   container_class->forall = gtk_tree_view_forall;
553   container_class->set_focus_child = gtk_tree_view_set_focus_child;
554
555   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
556   class->move_cursor = gtk_tree_view_real_move_cursor;
557   class->select_all = gtk_tree_view_real_select_all;
558   class->unselect_all = gtk_tree_view_real_unselect_all;
559   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
560   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
561   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
562   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
563   class->start_interactive_search = gtk_tree_view_start_interactive_search;
564
565   /* Properties */
566
567   g_object_class_install_property (o_class,
568                                    PROP_MODEL,
569                                    g_param_spec_object ("model",
570                                                         P_("TreeView Model"),
571                                                         P_("The model for the tree view"),
572                                                         GTK_TYPE_TREE_MODEL,
573                                                         GTK_PARAM_READWRITE));
574
575   g_object_class_install_property (o_class,
576                                    PROP_HADJUSTMENT,
577                                    g_param_spec_object ("hadjustment",
578                                                         P_("Horizontal Adjustment"),
579                                                         P_("Horizontal Adjustment for the widget"),
580                                                         GTK_TYPE_ADJUSTMENT,
581                                                         GTK_PARAM_READWRITE));
582
583   g_object_class_install_property (o_class,
584                                    PROP_VADJUSTMENT,
585                                    g_param_spec_object ("vadjustment",
586                                                         P_("Vertical Adjustment"),
587                                                         P_("Vertical Adjustment for the widget"),
588                                                         GTK_TYPE_ADJUSTMENT,
589                                                         GTK_PARAM_READWRITE));
590
591   g_object_class_install_property (o_class,
592                                    PROP_HEADERS_VISIBLE,
593                                    g_param_spec_boolean ("headers-visible",
594                                                          P_("Headers Visible"),
595                                                          P_("Show the column header buttons"),
596                                                          TRUE,
597                                                          GTK_PARAM_READWRITE));
598
599   g_object_class_install_property (o_class,
600                                    PROP_HEADERS_CLICKABLE,
601                                    g_param_spec_boolean ("headers-clickable",
602                                                          P_("Headers Clickable"),
603                                                          P_("Column headers respond to click events"),
604                                                          TRUE,
605                                                          GTK_PARAM_READWRITE));
606
607   g_object_class_install_property (o_class,
608                                    PROP_EXPANDER_COLUMN,
609                                    g_param_spec_object ("expander-column",
610                                                         P_("Expander Column"),
611                                                         P_("Set the column for the expander column"),
612                                                         GTK_TYPE_TREE_VIEW_COLUMN,
613                                                         GTK_PARAM_READWRITE));
614
615   g_object_class_install_property (o_class,
616                                    PROP_REORDERABLE,
617                                    g_param_spec_boolean ("reorderable",
618                                                          P_("Reorderable"),
619                                                          P_("View is reorderable"),
620                                                          FALSE,
621                                                          GTK_PARAM_READWRITE));
622
623   g_object_class_install_property (o_class,
624                                    PROP_RULES_HINT,
625                                    g_param_spec_boolean ("rules-hint",
626                                                          P_("Rules Hint"),
627                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
628                                                          FALSE,
629                                                          GTK_PARAM_READWRITE));
630
631     g_object_class_install_property (o_class,
632                                      PROP_ENABLE_SEARCH,
633                                      g_param_spec_boolean ("enable-search",
634                                                            P_("Enable Search"),
635                                                            P_("View allows user to search through columns interactively"),
636                                                            TRUE,
637                                                            GTK_PARAM_READWRITE));
638
639     g_object_class_install_property (o_class,
640                                      PROP_SEARCH_COLUMN,
641                                      g_param_spec_int ("search-column",
642                                                        P_("Search Column"),
643                                                        P_("Model column to search through during interactive search"),
644                                                        -1,
645                                                        G_MAXINT,
646                                                        -1,
647                                                        GTK_PARAM_READWRITE));
648
649     /**
650      * GtkTreeView:fixed-height-mode:
651      *
652      * Setting the ::fixed-height-mode property to %TRUE speeds up 
653      * #GtkTreeView by assuming that all rows have the same height. 
654      * Only enable this option if all rows are the same height.  
655      * Please see gtk_tree_view_set_fixed_height_mode() for more 
656      * information on this option.
657      *
658      * Since: 2.4
659      **/
660     g_object_class_install_property (o_class,
661                                      PROP_FIXED_HEIGHT_MODE,
662                                      g_param_spec_boolean ("fixed-height-mode",
663                                                            P_("Fixed Height Mode"),
664                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
665                                                            FALSE,
666                                                            GTK_PARAM_READWRITE));
667     
668     /**
669      * GtkTreeView:hover-selection:
670      * 
671      * Enables of disables the hover selection mode of @tree_view.
672      * Hover selection makes the selected row follow the pointer.
673      * Currently, this works only for the selection modes 
674      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
675      *
676      * This mode is primarily intended for treeviews in popups, e.g.
677      * in #GtkComboBox or #GtkEntryCompletion.
678      *
679      * Since: 2.6
680      */
681     g_object_class_install_property (o_class,
682                                      PROP_HOVER_SELECTION,
683                                      g_param_spec_boolean ("hover-selection",
684                                                            P_("Hover Selection"),
685                                                            P_("Whether the selection should follow the pointer"),
686                                                            FALSE,
687                                                            GTK_PARAM_READWRITE));
688
689     /**
690      * GtkTreeView:hover-expand:
691      * 
692      * Enables of disables the hover expansion mode of @tree_view.
693      * Hover expansion makes rows expand or collapse if the pointer moves 
694      * over them.
695      *
696      * This mode is primarily intended for treeviews in popups, e.g.
697      * in #GtkComboBox or #GtkEntryCompletion.
698      *
699      * Since: 2.6
700      */
701     g_object_class_install_property (o_class,
702                                      PROP_HOVER_EXPAND,
703                                      g_param_spec_boolean ("hover-expand",
704                                                            P_("Hover Expand"),
705                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
706                                                            FALSE,
707                                                            GTK_PARAM_READWRITE));
708
709     /**
710      * GtkTreeView:show-expanders:
711      *
712      * %TRUE if the view has expanders.
713      *
714      * Since: 2.12
715      */
716     g_object_class_install_property (o_class,
717                                      PROP_SHOW_EXPANDERS,
718                                      g_param_spec_boolean ("show-expanders",
719                                                            P_("Show Expanders"),
720                                                            P_("View has expanders"),
721                                                            TRUE,
722                                                            GTK_PARAM_READWRITE));
723
724     /**
725      * GtkTreeView:level-indentation:
726      *
727      * Extra indentation for each level.
728      *
729      * Since: 2.12
730      */
731     g_object_class_install_property (o_class,
732                                      PROP_LEVEL_INDENTATION,
733                                      g_param_spec_int ("level-indentation",
734                                                        P_("Level Indentation"),
735                                                        P_("Extra indentation for each level"),
736                                                        0,
737                                                        G_MAXINT,
738                                                        0,
739                                                        GTK_PARAM_READWRITE));
740
741     g_object_class_install_property (o_class,
742                                      PROP_RUBBER_BANDING,
743                                      g_param_spec_boolean ("rubber-banding",
744                                                            P_("Rubber Banding"),
745                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
746                                                            FALSE,
747                                                            GTK_PARAM_READWRITE));
748
749     g_object_class_install_property (o_class,
750                                      PROP_ENABLE_GRID_LINES,
751                                      g_param_spec_enum ("enable-grid-lines",
752                                                         P_("Enable Grid Lines"),
753                                                         P_("Whether grid lines should be drawn in the tree view"),
754                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
755                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
756                                                         GTK_PARAM_READWRITE));
757
758     g_object_class_install_property (o_class,
759                                      PROP_ENABLE_TREE_LINES,
760                                      g_param_spec_boolean ("enable-tree-lines",
761                                                            P_("Enable Tree Lines"),
762                                                            P_("Whether tree lines should be drawn in the tree view"),
763                                                            FALSE,
764                                                            GTK_PARAM_READWRITE));
765
766     g_object_class_install_property (o_class,
767                                      PROP_TOOLTIP_COLUMN,
768                                      g_param_spec_int ("tooltip-column",
769                                                        P_("Tooltip Column"),
770                                                        P_("The column in the model containing the tooltip texts for the rows"),
771                                                        -1,
772                                                        G_MAXINT,
773                                                        -1,
774                                                        GTK_PARAM_READWRITE));
775
776   /* Style properties */
777 #define _TREE_VIEW_EXPANDER_SIZE 12
778 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
779 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
780
781   gtk_widget_class_install_style_property (widget_class,
782                                            g_param_spec_int ("expander-size",
783                                                              P_("Expander Size"),
784                                                              P_("Size of the expander arrow"),
785                                                              0,
786                                                              G_MAXINT,
787                                                              _TREE_VIEW_EXPANDER_SIZE,
788                                                              GTK_PARAM_READABLE));
789
790   gtk_widget_class_install_style_property (widget_class,
791                                            g_param_spec_int ("vertical-separator",
792                                                              P_("Vertical Separator Width"),
793                                                              P_("Vertical space between cells.  Must be an even number"),
794                                                              0,
795                                                              G_MAXINT,
796                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
797                                                              GTK_PARAM_READABLE));
798
799   gtk_widget_class_install_style_property (widget_class,
800                                            g_param_spec_int ("horizontal-separator",
801                                                              P_("Horizontal Separator Width"),
802                                                              P_("Horizontal space between cells.  Must be an even number"),
803                                                              0,
804                                                              G_MAXINT,
805                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
806                                                              GTK_PARAM_READABLE));
807
808   gtk_widget_class_install_style_property (widget_class,
809                                            g_param_spec_boolean ("allow-rules",
810                                                                  P_("Allow Rules"),
811                                                                  P_("Allow drawing of alternating color rows"),
812                                                                  TRUE,
813                                                                  GTK_PARAM_READABLE));
814
815   gtk_widget_class_install_style_property (widget_class,
816                                            g_param_spec_boolean ("indent-expanders",
817                                                                  P_("Indent Expanders"),
818                                                                  P_("Make the expanders indented"),
819                                                                  TRUE,
820                                                                  GTK_PARAM_READABLE));
821
822   gtk_widget_class_install_style_property (widget_class,
823                                            g_param_spec_boxed ("even-row-color",
824                                                                P_("Even Row Color"),
825                                                                P_("Color to use for even rows"),
826                                                                GDK_TYPE_COLOR,
827                                                                GTK_PARAM_READABLE));
828
829   gtk_widget_class_install_style_property (widget_class,
830                                            g_param_spec_boxed ("odd-row-color",
831                                                                P_("Odd Row Color"),
832                                                                P_("Color to use for odd rows"),
833                                                                GDK_TYPE_COLOR,
834                                                                GTK_PARAM_READABLE));
835
836   gtk_widget_class_install_style_property (widget_class,
837                                            g_param_spec_boolean ("row-ending-details",
838                                                                  P_("Row Ending details"),
839                                                                  P_("Enable extended row background theming"),
840                                                                  FALSE,
841                                                                  GTK_PARAM_READABLE));
842
843   gtk_widget_class_install_style_property (widget_class,
844                                            g_param_spec_int ("grid-line-width",
845                                                              P_("Grid line width"),
846                                                              P_("Width, in pixels, of the tree view grid lines"),
847                                                              0, G_MAXINT, 1,
848                                                              GTK_PARAM_READABLE));
849
850   gtk_widget_class_install_style_property (widget_class,
851                                            g_param_spec_int ("tree-line-width",
852                                                              P_("Tree line width"),
853                                                              P_("Width, in pixels, of the tree view lines"),
854                                                              0, G_MAXINT, 1,
855                                                              GTK_PARAM_READABLE));
856
857   gtk_widget_class_install_style_property (widget_class,
858                                            g_param_spec_string ("grid-line-pattern",
859                                                                 P_("Grid line pattern"),
860                                                                 P_("Dash pattern used to draw the tree view grid lines"),
861                                                                 "\1\1",
862                                                                 GTK_PARAM_READABLE));
863
864   gtk_widget_class_install_style_property (widget_class,
865                                            g_param_spec_string ("tree-line-pattern",
866                                                                 P_("Tree line pattern"),
867                                                                 P_("Dash pattern used to draw the tree view lines"),
868                                                                 "\1\1",
869                                                                 GTK_PARAM_READABLE));
870
871   /* Signals */
872   /**
873    * GtkTreeView::set-scroll-adjustments
874    * @horizontal: the horizontal #GtkAdjustment
875    * @vertical: the vertical #GtkAdjustment
876    *
877    * Set the scroll adjustments for the tree view. Usually scrolled containers
878    * like #GtkScrolledWindow will emit this signal to connect two instances
879    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
880    */
881   widget_class->set_scroll_adjustments_signal =
882     g_signal_new (I_("set-scroll-adjustments"),
883                   G_TYPE_FROM_CLASS (o_class),
884                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
885                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
886                   NULL, NULL,
887                   _gtk_marshal_VOID__OBJECT_OBJECT,
888                   G_TYPE_NONE, 2,
889                   GTK_TYPE_ADJUSTMENT,
890                   GTK_TYPE_ADJUSTMENT);
891
892   /**
893    * GtkTreeView::row-activated:
894    * @tree_view: the object on which the signal is emitted
895    * @path: the #GtkTreePath for the activated row
896    * @column: the #GtkTreeViewColumn in which the activation occurred
897    *
898    * The "row-activated" signal is emitted when the method
899    * gtk_tree_view_row_activated() is called or the user double clicks 
900    * a treeview row. It is also emitted when a non-editable row is 
901    * selected and one of the keys: Space, Shift+Space, Return or 
902    * Enter is pressed.
903    * 
904    * For selection handling refer to the <link linkend="TreeWidget">tree 
905    * widget conceptual overview</link> as well as #GtkTreeSelection.
906    */
907   tree_view_signals[ROW_ACTIVATED] =
908     g_signal_new (I_("row-activated"),
909                   G_TYPE_FROM_CLASS (o_class),
910                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
911                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
912                   NULL, NULL,
913                   _gtk_marshal_VOID__BOXED_OBJECT,
914                   G_TYPE_NONE, 2,
915                   GTK_TYPE_TREE_PATH,
916                   GTK_TYPE_TREE_VIEW_COLUMN);
917
918   /**
919    * GtkTreeView::test-expand-row:
920    * @tree_view: the object on which the signal is emitted
921    * @iter: the tree iter of the row to expand
922    * @path: a tree path that points to the row 
923    * 
924    * The given row is about to be expanded (show its children nodes). Use this
925    * signal if you need to control the expandability of individual rows.
926    *
927    * Returns: %FALSE to allow expansion, %TRUE to reject
928    */
929   tree_view_signals[TEST_EXPAND_ROW] =
930     g_signal_new (I_("test-expand-row"),
931                   G_TYPE_FROM_CLASS (o_class),
932                   G_SIGNAL_RUN_LAST,
933                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
934                   _gtk_boolean_handled_accumulator, NULL,
935                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
936                   G_TYPE_BOOLEAN, 2,
937                   GTK_TYPE_TREE_ITER,
938                   GTK_TYPE_TREE_PATH);
939
940   /**
941    * GtkTreeView::test-collapse-row:
942    * @tree_view: the object on which the signal is emitted
943    * @iter: the tree iter of the row to collapse
944    * @path: a tree path that points to the row 
945    * 
946    * The given row is about to be collapsed (hide its children nodes). Use this
947    * signal if you need to control the collapsibility of individual rows.
948    *
949    * Returns: %FALSE to allow collapsing, %TRUE to reject
950    */
951   tree_view_signals[TEST_COLLAPSE_ROW] =
952     g_signal_new (I_("test-collapse-row"),
953                   G_TYPE_FROM_CLASS (o_class),
954                   G_SIGNAL_RUN_LAST,
955                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
956                   _gtk_boolean_handled_accumulator, NULL,
957                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
958                   G_TYPE_BOOLEAN, 2,
959                   GTK_TYPE_TREE_ITER,
960                   GTK_TYPE_TREE_PATH);
961
962   /**
963    * GtkTreeView::row-expanded:
964    * @tree_view: the object on which the signal is emitted
965    * @iter: the tree iter of the expanded row
966    * @path: a tree path that points to the row 
967    * 
968    * The given row has been expanded (child nodes are shown).
969    */
970   tree_view_signals[ROW_EXPANDED] =
971     g_signal_new (I_("row-expanded"),
972                   G_TYPE_FROM_CLASS (o_class),
973                   G_SIGNAL_RUN_LAST,
974                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
975                   NULL, NULL,
976                   _gtk_marshal_VOID__BOXED_BOXED,
977                   G_TYPE_NONE, 2,
978                   GTK_TYPE_TREE_ITER,
979                   GTK_TYPE_TREE_PATH);
980
981   /**
982    * GtkTreeView::row-collapsed:
983    * @tree_view: the object on which the signal is emitted
984    * @iter: the tree iter of the collapsed row
985    * @path: a tree path that points to the row 
986    * 
987    * The given row has been collapsed (child nodes are hidden).
988    */
989   tree_view_signals[ROW_COLLAPSED] =
990     g_signal_new (I_("row-collapsed"),
991                   G_TYPE_FROM_CLASS (o_class),
992                   G_SIGNAL_RUN_LAST,
993                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
994                   NULL, NULL,
995                   _gtk_marshal_VOID__BOXED_BOXED,
996                   G_TYPE_NONE, 2,
997                   GTK_TYPE_TREE_ITER,
998                   GTK_TYPE_TREE_PATH);
999
1000   /**
1001    * GtkTreeView::columns-changed:
1002    * @tree_view: the object on which the signal is emitted 
1003    * 
1004    * The number of columns of the treeview has changed.
1005    */
1006   tree_view_signals[COLUMNS_CHANGED] =
1007     g_signal_new (I_("columns-changed"),
1008                   G_TYPE_FROM_CLASS (o_class),
1009                   G_SIGNAL_RUN_LAST,
1010                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1011                   NULL, NULL,
1012                   _gtk_marshal_VOID__VOID,
1013                   G_TYPE_NONE, 0);
1014
1015   /**
1016    * GtkTreeView::cursor-changed:
1017    * @tree_view: the object on which the signal is emitted
1018    * 
1019    * The position of the cursor (focused cell) has changed.
1020    */
1021   tree_view_signals[CURSOR_CHANGED] =
1022     g_signal_new (I_("cursor-changed"),
1023                   G_TYPE_FROM_CLASS (o_class),
1024                   G_SIGNAL_RUN_LAST,
1025                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1026                   NULL, NULL,
1027                   _gtk_marshal_VOID__VOID,
1028                   G_TYPE_NONE, 0);
1029
1030   tree_view_signals[MOVE_CURSOR] =
1031     g_signal_new (I_("move-cursor"),
1032                   G_TYPE_FROM_CLASS (object_class),
1033                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1034                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1035                   NULL, NULL,
1036                   _gtk_marshal_BOOLEAN__ENUM_INT,
1037                   G_TYPE_BOOLEAN, 2,
1038                   GTK_TYPE_MOVEMENT_STEP,
1039                   G_TYPE_INT);
1040
1041   tree_view_signals[SELECT_ALL] =
1042     g_signal_new (I_("select-all"),
1043                   G_TYPE_FROM_CLASS (object_class),
1044                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1045                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1046                   NULL, NULL,
1047                   _gtk_marshal_BOOLEAN__VOID,
1048                   G_TYPE_BOOLEAN, 0);
1049
1050   tree_view_signals[UNSELECT_ALL] =
1051     g_signal_new (I_("unselect-all"),
1052                   G_TYPE_FROM_CLASS (object_class),
1053                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1054                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1055                   NULL, NULL,
1056                   _gtk_marshal_BOOLEAN__VOID,
1057                   G_TYPE_BOOLEAN, 0);
1058
1059   tree_view_signals[SELECT_CURSOR_ROW] =
1060     g_signal_new (I_("select-cursor-row"),
1061                   G_TYPE_FROM_CLASS (object_class),
1062                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1063                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1064                   NULL, NULL,
1065                   _gtk_marshal_BOOLEAN__BOOLEAN,
1066                   G_TYPE_BOOLEAN, 1,
1067                   G_TYPE_BOOLEAN);
1068
1069   tree_view_signals[TOGGLE_CURSOR_ROW] =
1070     g_signal_new (I_("toggle-cursor-row"),
1071                   G_TYPE_FROM_CLASS (object_class),
1072                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1073                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1074                   NULL, NULL,
1075                   _gtk_marshal_BOOLEAN__VOID,
1076                   G_TYPE_BOOLEAN, 0);
1077
1078   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1079     g_signal_new (I_("expand-collapse-cursor-row"),
1080                   G_TYPE_FROM_CLASS (object_class),
1081                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1082                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1083                   NULL, NULL,
1084                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1085                   G_TYPE_BOOLEAN, 3,
1086                   G_TYPE_BOOLEAN,
1087                   G_TYPE_BOOLEAN,
1088                   G_TYPE_BOOLEAN);
1089
1090   tree_view_signals[SELECT_CURSOR_PARENT] =
1091     g_signal_new (I_("select-cursor-parent"),
1092                   G_TYPE_FROM_CLASS (object_class),
1093                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1094                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1095                   NULL, NULL,
1096                   _gtk_marshal_BOOLEAN__VOID,
1097                   G_TYPE_BOOLEAN, 0);
1098
1099   tree_view_signals[START_INTERACTIVE_SEARCH] =
1100     g_signal_new (I_("start-interactive-search"),
1101                   G_TYPE_FROM_CLASS (object_class),
1102                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1103                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1104                   NULL, NULL,
1105                   _gtk_marshal_BOOLEAN__VOID,
1106                   G_TYPE_BOOLEAN, 0);
1107
1108   /* Key bindings */
1109   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1110                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1111   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1112                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1113
1114   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1115                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1116   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1117                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1118
1119   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1120                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1121
1122   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1123                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1124
1125   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1126                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1127   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1128                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1129
1130   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1131                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1132   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1133                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1134
1135   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1136                                   GTK_MOVEMENT_PAGES, -1);
1137   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1138                                   GTK_MOVEMENT_PAGES, -1);
1139
1140   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1141                                   GTK_MOVEMENT_PAGES, 1);
1142   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1143                                   GTK_MOVEMENT_PAGES, 1);
1144
1145
1146   gtk_binding_entry_add_signal (binding_set, GDK_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_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_KP_Right, 0, "move-cursor", 2,
1155                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1156                                 G_TYPE_INT, 1);
1157
1158   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2,
1159                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1160                                 G_TYPE_INT, -1);
1161
1162   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1163                                 "move-cursor", 2,
1164                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1165                                 G_TYPE_INT, 1);
1166
1167   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1168                                 "move-cursor", 2,
1169                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1170                                 G_TYPE_INT, -1);
1171
1172   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1173                                 "move-cursor", 2,
1174                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1175                                 G_TYPE_INT, 1);
1176
1177   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1178                                 "move-cursor", 2,
1179                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1180                                 G_TYPE_INT, -1);
1181
1182   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1183   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1184
1185   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
1186   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
1187
1188   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1189   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1190
1191   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1194                                 G_TYPE_BOOLEAN, TRUE);
1195
1196   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
1199                                 G_TYPE_BOOLEAN, TRUE);
1200   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
1201                                 G_TYPE_BOOLEAN, TRUE);
1202   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
1203                                 G_TYPE_BOOLEAN, TRUE);
1204   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
1205                                 G_TYPE_BOOLEAN, TRUE);
1206
1207   /* expand and collapse rows */
1208   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3,
1209                                 G_TYPE_BOOLEAN, TRUE,
1210                                 G_TYPE_BOOLEAN, TRUE,
1211                                 G_TYPE_BOOLEAN, FALSE);
1212
1213   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1214                                 "expand-collapse-cursor-row", 3,
1215                                 G_TYPE_BOOLEAN, TRUE,
1216                                 G_TYPE_BOOLEAN, TRUE,
1217                                 G_TYPE_BOOLEAN, TRUE);
1218   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1219                                 "expand-collapse-cursor-row", 3,
1220                                 G_TYPE_BOOLEAN, TRUE,
1221                                 G_TYPE_BOOLEAN, TRUE,
1222                                 G_TYPE_BOOLEAN, TRUE);
1223
1224   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1225                                 "expand-collapse-cursor-row", 3,
1226                                 G_TYPE_BOOLEAN, TRUE,
1227                                 G_TYPE_BOOLEAN, FALSE,
1228                                 G_TYPE_BOOLEAN, FALSE);
1229   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1230                                 "expand-collapse-cursor-row", 3,
1231                                 G_TYPE_BOOLEAN, TRUE,
1232                                 G_TYPE_BOOLEAN, FALSE,
1233                                 G_TYPE_BOOLEAN, FALSE);
1234
1235   /* Not doable on US keyboards */
1236   gtk_binding_entry_add_signal (binding_set, GDK_plus, 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_KP_Add, 0, "expand-collapse-cursor-row", 3,
1241                                 G_TYPE_BOOLEAN, TRUE,
1242                                 G_TYPE_BOOLEAN, TRUE,
1243                                 G_TYPE_BOOLEAN, FALSE);
1244   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1245                                 G_TYPE_BOOLEAN, TRUE,
1246                                 G_TYPE_BOOLEAN, TRUE,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1249                                 G_TYPE_BOOLEAN, TRUE,
1250                                 G_TYPE_BOOLEAN, TRUE,
1251                                 G_TYPE_BOOLEAN, TRUE);
1252   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1253                                 "expand-collapse-cursor-row", 3,
1254                                 G_TYPE_BOOLEAN, FALSE,
1255                                 G_TYPE_BOOLEAN, TRUE,
1256                                 G_TYPE_BOOLEAN, TRUE);
1257   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1258                                 "expand-collapse-cursor-row", 3,
1259                                 G_TYPE_BOOLEAN, FALSE,
1260                                 G_TYPE_BOOLEAN, TRUE,
1261                                 G_TYPE_BOOLEAN, TRUE);
1262   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1263                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1264                                 "expand-collapse-cursor-row", 3,
1265                                 G_TYPE_BOOLEAN, FALSE,
1266                                 G_TYPE_BOOLEAN, TRUE,
1267                                 G_TYPE_BOOLEAN, TRUE);
1268   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1269                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1270                                 "expand-collapse-cursor-row", 3,
1271                                 G_TYPE_BOOLEAN, FALSE,
1272                                 G_TYPE_BOOLEAN, TRUE,
1273                                 G_TYPE_BOOLEAN, TRUE);
1274
1275   gtk_binding_entry_add_signal (binding_set, GDK_minus, 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_minus, 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_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1284                                 G_TYPE_BOOLEAN, TRUE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, FALSE);
1287   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1288                                 G_TYPE_BOOLEAN, TRUE,
1289                                 G_TYPE_BOOLEAN, FALSE,
1290                                 G_TYPE_BOOLEAN, TRUE);
1291   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1292                                 "expand-collapse-cursor-row", 3,
1293                                 G_TYPE_BOOLEAN, FALSE,
1294                                 G_TYPE_BOOLEAN, FALSE,
1295                                 G_TYPE_BOOLEAN, TRUE);
1296   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1297                                 "expand-collapse-cursor-row", 3,
1298                                 G_TYPE_BOOLEAN, FALSE,
1299                                 G_TYPE_BOOLEAN, FALSE,
1300                                 G_TYPE_BOOLEAN, TRUE);
1301   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1302                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1303                                 "expand-collapse-cursor-row", 3,
1304                                 G_TYPE_BOOLEAN, FALSE,
1305                                 G_TYPE_BOOLEAN, FALSE,
1306                                 G_TYPE_BOOLEAN, TRUE);
1307   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1308                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1309                                 "expand-collapse-cursor-row", 3,
1310                                 G_TYPE_BOOLEAN, FALSE,
1311                                 G_TYPE_BOOLEAN, FALSE,
1312                                 G_TYPE_BOOLEAN, TRUE);
1313
1314   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
1315   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1316
1317   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1318
1319   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1320
1321   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1322 }
1323
1324 static void
1325 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1326 {
1327   iface->add_child = gtk_tree_view_buildable_add_child;
1328 }
1329
1330 static void
1331 gtk_tree_view_init (GtkTreeView *tree_view)
1332 {
1333   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1334
1335   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
1336
1337   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1338
1339   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1340                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1341                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1342
1343   /* We need some padding */
1344   tree_view->priv->dy = 0;
1345   tree_view->priv->cursor_offset = 0;
1346   tree_view->priv->n_columns = 0;
1347   tree_view->priv->header_height = 1;
1348   tree_view->priv->x_drag = 0;
1349   tree_view->priv->drag_pos = -1;
1350   tree_view->priv->header_has_focus = FALSE;
1351   tree_view->priv->pressed_button = -1;
1352   tree_view->priv->press_start_x = -1;
1353   tree_view->priv->press_start_y = -1;
1354   tree_view->priv->reorderable = FALSE;
1355   tree_view->priv->presize_handler_timer = 0;
1356   tree_view->priv->scroll_sync_timer = 0;
1357   tree_view->priv->fixed_height = -1;
1358   tree_view->priv->fixed_height_mode = FALSE;
1359   tree_view->priv->fixed_height_check = 0;
1360   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1361   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1362   tree_view->priv->enable_search = TRUE;
1363   tree_view->priv->search_column = -1;
1364   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1365   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1366   tree_view->priv->search_custom_entry_set = FALSE;
1367   tree_view->priv->typeselect_flush_timeout = 0;
1368   tree_view->priv->init_hadjust_value = TRUE;    
1369   tree_view->priv->width = 0;
1370           
1371   tree_view->priv->hover_selection = FALSE;
1372   tree_view->priv->hover_expand = FALSE;
1373
1374   tree_view->priv->level_indentation = 0;
1375
1376   tree_view->priv->rubber_banding_enable = FALSE;
1377
1378   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1379   tree_view->priv->tree_lines_enabled = FALSE;
1380
1381   tree_view->priv->tooltip_column = -1;
1382
1383   tree_view->priv->post_validation_flag = FALSE;
1384 }
1385
1386 \f
1387
1388 /* GObject Methods
1389  */
1390
1391 static void
1392 gtk_tree_view_set_property (GObject         *object,
1393                             guint            prop_id,
1394                             const GValue    *value,
1395                             GParamSpec      *pspec)
1396 {
1397   GtkTreeView *tree_view;
1398
1399   tree_view = GTK_TREE_VIEW (object);
1400
1401   switch (prop_id)
1402     {
1403     case PROP_MODEL:
1404       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1405       break;
1406     case PROP_HADJUSTMENT:
1407       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1408       break;
1409     case PROP_VADJUSTMENT:
1410       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1411       break;
1412     case PROP_HEADERS_VISIBLE:
1413       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1414       break;
1415     case PROP_HEADERS_CLICKABLE:
1416       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1417       break;
1418     case PROP_EXPANDER_COLUMN:
1419       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1420       break;
1421     case PROP_REORDERABLE:
1422       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1423       break;
1424     case PROP_RULES_HINT:
1425       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1426       break;
1427     case PROP_ENABLE_SEARCH:
1428       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1429       break;
1430     case PROP_SEARCH_COLUMN:
1431       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1432       break;
1433     case PROP_FIXED_HEIGHT_MODE:
1434       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1435       break;
1436     case PROP_HOVER_SELECTION:
1437       tree_view->priv->hover_selection = g_value_get_boolean (value);
1438       break;
1439     case PROP_HOVER_EXPAND:
1440       tree_view->priv->hover_expand = g_value_get_boolean (value);
1441       break;
1442     case PROP_SHOW_EXPANDERS:
1443       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1444       break;
1445     case PROP_LEVEL_INDENTATION:
1446       tree_view->priv->level_indentation = g_value_get_int (value);
1447       break;
1448     case PROP_RUBBER_BANDING:
1449       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1450       break;
1451     case PROP_ENABLE_GRID_LINES:
1452       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1453       break;
1454     case PROP_ENABLE_TREE_LINES:
1455       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1456       break;
1457     case PROP_TOOLTIP_COLUMN:
1458       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1459       break;
1460     default:
1461       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1462       break;
1463     }
1464 }
1465
1466 static void
1467 gtk_tree_view_get_property (GObject    *object,
1468                             guint       prop_id,
1469                             GValue     *value,
1470                             GParamSpec *pspec)
1471 {
1472   GtkTreeView *tree_view;
1473
1474   tree_view = GTK_TREE_VIEW (object);
1475
1476   switch (prop_id)
1477     {
1478     case PROP_MODEL:
1479       g_value_set_object (value, tree_view->priv->model);
1480       break;
1481     case PROP_HADJUSTMENT:
1482       g_value_set_object (value, tree_view->priv->hadjustment);
1483       break;
1484     case PROP_VADJUSTMENT:
1485       g_value_set_object (value, tree_view->priv->vadjustment);
1486       break;
1487     case PROP_HEADERS_VISIBLE:
1488       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1489       break;
1490     case PROP_HEADERS_CLICKABLE:
1491       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1492       break;
1493     case PROP_EXPANDER_COLUMN:
1494       g_value_set_object (value, tree_view->priv->expander_column);
1495       break;
1496     case PROP_REORDERABLE:
1497       g_value_set_boolean (value, tree_view->priv->reorderable);
1498       break;
1499     case PROP_RULES_HINT:
1500       g_value_set_boolean (value, tree_view->priv->has_rules);
1501       break;
1502     case PROP_ENABLE_SEARCH:
1503       g_value_set_boolean (value, tree_view->priv->enable_search);
1504       break;
1505     case PROP_SEARCH_COLUMN:
1506       g_value_set_int (value, tree_view->priv->search_column);
1507       break;
1508     case PROP_FIXED_HEIGHT_MODE:
1509       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1510       break;
1511     case PROP_HOVER_SELECTION:
1512       g_value_set_boolean (value, tree_view->priv->hover_selection);
1513       break;
1514     case PROP_HOVER_EXPAND:
1515       g_value_set_boolean (value, tree_view->priv->hover_expand);
1516       break;
1517     case PROP_SHOW_EXPANDERS:
1518       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1519       break;
1520     case PROP_LEVEL_INDENTATION:
1521       g_value_set_int (value, tree_view->priv->level_indentation);
1522       break;
1523     case PROP_RUBBER_BANDING:
1524       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1525       break;
1526     case PROP_ENABLE_GRID_LINES:
1527       g_value_set_enum (value, tree_view->priv->grid_lines);
1528       break;
1529     case PROP_ENABLE_TREE_LINES:
1530       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1531       break;
1532     case PROP_TOOLTIP_COLUMN:
1533       g_value_set_int (value, tree_view->priv->tooltip_column);
1534       break;
1535     default:
1536       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1537       break;
1538     }
1539 }
1540
1541 static void
1542 gtk_tree_view_finalize (GObject *object)
1543 {
1544   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1545 }
1546
1547 \f
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 /* GtkObject Methods
1559  */
1560
1561 static void
1562 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1563 {
1564   _gtk_rbtree_free (tree_view->priv->tree);
1565   
1566   tree_view->priv->tree = NULL;
1567   tree_view->priv->button_pressed_node = NULL;
1568   tree_view->priv->button_pressed_tree = NULL;
1569   tree_view->priv->prelight_tree = NULL;
1570   tree_view->priv->prelight_node = NULL;
1571   tree_view->priv->expanded_collapsed_node = NULL;
1572   tree_view->priv->expanded_collapsed_tree = NULL;
1573 }
1574
1575 static void
1576 gtk_tree_view_destroy (GtkObject *object)
1577 {
1578   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1579   GList *list;
1580
1581   gtk_tree_view_stop_editing (tree_view, TRUE);
1582
1583   if (tree_view->priv->columns != NULL)
1584     {
1585       list = tree_view->priv->columns;
1586       while (list)
1587         {
1588           GtkTreeViewColumn *column;
1589           column = GTK_TREE_VIEW_COLUMN (list->data);
1590           list = list->next;
1591           gtk_tree_view_remove_column (tree_view, column);
1592         }
1593       tree_view->priv->columns = NULL;
1594     }
1595
1596   if (tree_view->priv->tree != NULL)
1597     {
1598       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1599
1600       gtk_tree_view_free_rbtree (tree_view);
1601     }
1602
1603   if (tree_view->priv->selection != NULL)
1604     {
1605       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1606       g_object_unref (tree_view->priv->selection);
1607       tree_view->priv->selection = NULL;
1608     }
1609
1610   if (tree_view->priv->scroll_to_path != NULL)
1611     {
1612       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1613       tree_view->priv->scroll_to_path = NULL;
1614     }
1615
1616   if (tree_view->priv->drag_dest_row != NULL)
1617     {
1618       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1619       tree_view->priv->drag_dest_row = NULL;
1620     }
1621
1622   if (tree_view->priv->last_button_press != NULL)
1623     {
1624       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1625       tree_view->priv->last_button_press = NULL;
1626     }
1627
1628   if (tree_view->priv->last_button_press_2 != NULL)
1629     {
1630       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
1631       tree_view->priv->last_button_press_2 = NULL;
1632     }
1633
1634   if (tree_view->priv->top_row != NULL)
1635     {
1636       gtk_tree_row_reference_free (tree_view->priv->top_row);
1637       tree_view->priv->top_row = NULL;
1638     }
1639
1640   if (tree_view->priv->column_drop_func_data &&
1641       tree_view->priv->column_drop_func_data_destroy)
1642     {
1643       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1644       tree_view->priv->column_drop_func_data = NULL;
1645     }
1646
1647   if (tree_view->priv->destroy_count_destroy &&
1648       tree_view->priv->destroy_count_data)
1649     {
1650       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1651       tree_view->priv->destroy_count_data = NULL;
1652     }
1653
1654   gtk_tree_row_reference_free (tree_view->priv->cursor);
1655   tree_view->priv->cursor = NULL;
1656
1657   gtk_tree_row_reference_free (tree_view->priv->anchor);
1658   tree_view->priv->anchor = NULL;
1659
1660   /* destroy interactive search dialog */
1661   if (tree_view->priv->search_window)
1662     {
1663       gtk_widget_destroy (tree_view->priv->search_window);
1664       tree_view->priv->search_window = NULL;
1665       tree_view->priv->search_entry = NULL;
1666       if (tree_view->priv->typeselect_flush_timeout)
1667         {
1668           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1669           tree_view->priv->typeselect_flush_timeout = 0;
1670         }
1671     }
1672
1673   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1674     {
1675       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1676       tree_view->priv->search_user_data = NULL;
1677     }
1678
1679   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1680     {
1681       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1682       tree_view->priv->search_position_user_data = NULL;
1683     }
1684
1685   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1686     {
1687       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1688       tree_view->priv->row_separator_data = NULL;
1689     }
1690   
1691   gtk_tree_view_set_model (tree_view, NULL);
1692
1693   if (tree_view->priv->hadjustment)
1694     {
1695       g_object_unref (tree_view->priv->hadjustment);
1696       tree_view->priv->hadjustment = NULL;
1697     }
1698   if (tree_view->priv->vadjustment)
1699     {
1700       g_object_unref (tree_view->priv->vadjustment);
1701       tree_view->priv->vadjustment = NULL;
1702     }
1703
1704   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1705 }
1706
1707 \f
1708
1709 /* GtkWidget Methods
1710  */
1711
1712 /* GtkWidget::map helper */
1713 static void
1714 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1715 {
1716   GList *list;
1717
1718   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1719
1720   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1721     {
1722       GtkTreeViewColumn *column;
1723
1724       for (list = tree_view->priv->columns; list; list = list->next)
1725         {
1726           column = list->data;
1727           if (GTK_WIDGET_VISIBLE (column->button) &&
1728               !GTK_WIDGET_MAPPED (column->button))
1729             gtk_widget_map (column->button);
1730         }
1731       for (list = tree_view->priv->columns; list; list = list->next)
1732         {
1733           column = list->data;
1734           if (column->visible == FALSE)
1735             continue;
1736           if (column->resizable)
1737             {
1738               gdk_window_raise (column->window);
1739               gdk_window_show (column->window);
1740             }
1741           else
1742             gdk_window_hide (column->window);
1743         }
1744       gdk_window_show (tree_view->priv->header_window);
1745     }
1746 }
1747
1748 static void
1749 gtk_tree_view_map (GtkWidget *widget)
1750 {
1751   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1752   GList *tmp_list;
1753
1754   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1755
1756   tmp_list = tree_view->priv->children;
1757   while (tmp_list)
1758     {
1759       GtkTreeViewChild *child = tmp_list->data;
1760       tmp_list = tmp_list->next;
1761
1762       if (GTK_WIDGET_VISIBLE (child->widget))
1763         {
1764           if (!GTK_WIDGET_MAPPED (child->widget))
1765             gtk_widget_map (child->widget);
1766         }
1767     }
1768   gdk_window_show (tree_view->priv->bin_window);
1769
1770   gtk_tree_view_map_buttons (tree_view);
1771
1772   gdk_window_show (widget->window);
1773 }
1774
1775 static void
1776 gtk_tree_view_realize (GtkWidget *widget)
1777 {
1778   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1779   GList *tmp_list;
1780   GdkWindowAttr attributes;
1781   gint attributes_mask;
1782
1783   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1784
1785   /* Make the main, clipping window */
1786   attributes.window_type = GDK_WINDOW_CHILD;
1787   attributes.x = widget->allocation.x;
1788   attributes.y = widget->allocation.y;
1789   attributes.width = widget->allocation.width;
1790   attributes.height = widget->allocation.height;
1791   attributes.wclass = GDK_INPUT_OUTPUT;
1792   attributes.visual = gtk_widget_get_visual (widget);
1793   attributes.colormap = gtk_widget_get_colormap (widget);
1794   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1795
1796   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1797
1798   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1799                                    &attributes, attributes_mask);
1800   gdk_window_set_user_data (widget->window, widget);
1801
1802   /* Make the window for the tree */
1803   attributes.x = 0;
1804   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1805   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1806   attributes.height = widget->allocation.height;
1807   attributes.event_mask = (GDK_EXPOSURE_MASK |
1808                            GDK_SCROLL_MASK |
1809                            GDK_POINTER_MOTION_MASK |
1810                            GDK_ENTER_NOTIFY_MASK |
1811                            GDK_LEAVE_NOTIFY_MASK |
1812                            GDK_BUTTON_PRESS_MASK |
1813                            GDK_BUTTON_RELEASE_MASK |
1814                            gtk_widget_get_events (widget));
1815
1816   tree_view->priv->bin_window = gdk_window_new (widget->window,
1817                                                 &attributes, attributes_mask);
1818   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1819
1820   /* Make the column header window */
1821   attributes.x = 0;
1822   attributes.y = 0;
1823   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1824   attributes.height = tree_view->priv->header_height;
1825   attributes.event_mask = (GDK_EXPOSURE_MASK |
1826                            GDK_SCROLL_MASK |
1827                            GDK_BUTTON_PRESS_MASK |
1828                            GDK_BUTTON_RELEASE_MASK |
1829                            GDK_KEY_PRESS_MASK |
1830                            GDK_KEY_RELEASE_MASK |
1831                            gtk_widget_get_events (widget));
1832
1833   tree_view->priv->header_window = gdk_window_new (widget->window,
1834                                                    &attributes, attributes_mask);
1835   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1836
1837   /* Add them all up. */
1838   widget->style = gtk_style_attach (widget->style, widget->window);
1839   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1840   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1841   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1842
1843   tmp_list = tree_view->priv->children;
1844   while (tmp_list)
1845     {
1846       GtkTreeViewChild *child = tmp_list->data;
1847       tmp_list = tmp_list->next;
1848
1849       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1850     }
1851
1852   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1853     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1854
1855   /* Need to call those here, since they create GCs */
1856   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1857   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1858
1859   install_presize_handler (tree_view); 
1860 }
1861
1862 static void
1863 gtk_tree_view_unrealize (GtkWidget *widget)
1864 {
1865   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1866   GtkTreeViewPrivate *priv = tree_view->priv;
1867   GList *list;
1868
1869   if (priv->scroll_timeout != 0)
1870     {
1871       g_source_remove (priv->scroll_timeout);
1872       priv->scroll_timeout = 0;
1873     }
1874
1875   if (priv->auto_expand_timeout != 0)
1876     {
1877       g_source_remove (priv->auto_expand_timeout);
1878       priv->auto_expand_timeout = 0;
1879     }
1880
1881   if (priv->open_dest_timeout != 0)
1882     {
1883       g_source_remove (priv->open_dest_timeout);
1884       priv->open_dest_timeout = 0;
1885     }
1886
1887   remove_expand_collapse_timeout (tree_view);
1888   
1889   if (priv->presize_handler_timer != 0)
1890     {
1891       g_source_remove (priv->presize_handler_timer);
1892       priv->presize_handler_timer = 0;
1893     }
1894
1895   if (priv->validate_rows_timer != 0)
1896     {
1897       g_source_remove (priv->validate_rows_timer);
1898       priv->validate_rows_timer = 0;
1899     }
1900
1901   if (priv->scroll_sync_timer != 0)
1902     {
1903       g_source_remove (priv->scroll_sync_timer);
1904       priv->scroll_sync_timer = 0;
1905     }
1906
1907   if (priv->typeselect_flush_timeout)
1908     {
1909       g_source_remove (priv->typeselect_flush_timeout);
1910       priv->typeselect_flush_timeout = 0;
1911     }
1912   
1913   for (list = priv->columns; list; list = list->next)
1914     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1915
1916   gdk_window_set_user_data (priv->bin_window, NULL);
1917   gdk_window_destroy (priv->bin_window);
1918   priv->bin_window = NULL;
1919
1920   gdk_window_set_user_data (priv->header_window, NULL);
1921   gdk_window_destroy (priv->header_window);
1922   priv->header_window = NULL;
1923
1924   if (priv->drag_window)
1925     {
1926       gdk_window_set_user_data (priv->drag_window, NULL);
1927       gdk_window_destroy (priv->drag_window);
1928       priv->drag_window = NULL;
1929     }
1930
1931   if (priv->drag_highlight_window)
1932     {
1933       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1934       gdk_window_destroy (priv->drag_highlight_window);
1935       priv->drag_highlight_window = NULL;
1936     }
1937
1938   if (priv->tree_line_gc)
1939     {
1940       g_object_unref (priv->tree_line_gc);
1941       priv->tree_line_gc = NULL;
1942     }
1943
1944   if (priv->grid_line_gc)
1945     {
1946       g_object_unref (priv->grid_line_gc);
1947       priv->grid_line_gc = NULL;
1948     }
1949
1950   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1951 }
1952
1953 /* GtkWidget::size_request helper */
1954 static void
1955 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1956 {
1957   GList *list;
1958
1959   tree_view->priv->header_height = 0;
1960
1961   if (tree_view->priv->model)
1962     {
1963       for (list = tree_view->priv->columns; list; list = list->next)
1964         {
1965           GtkRequisition requisition;
1966           GtkTreeViewColumn *column = list->data;
1967
1968           if (column->button == NULL)
1969             continue;
1970
1971           column = list->data;
1972           
1973           gtk_widget_size_request (column->button, &requisition);
1974           column->button_request = requisition.width;
1975           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1976         }
1977     }
1978 }
1979
1980
1981 /* Called only by ::size_request */
1982 static void
1983 gtk_tree_view_update_size (GtkTreeView *tree_view)
1984 {
1985   GList *list;
1986   GtkTreeViewColumn *column;
1987   gint i;
1988
1989   if (tree_view->priv->model == NULL)
1990     {
1991       tree_view->priv->width = 0;
1992       tree_view->priv->prev_width = 0;                   
1993       tree_view->priv->height = 0;
1994       return;
1995     }
1996
1997   tree_view->priv->prev_width = tree_view->priv->width;  
1998   tree_view->priv->width = 0;
1999
2000   /* keep this in sync with size_allocate below */
2001   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2002     {
2003       gint real_requested_width = 0;
2004       column = list->data;
2005       if (!column->visible)
2006         continue;
2007
2008       if (column->use_resized_width)
2009         {
2010           real_requested_width = column->resized_width;
2011         }
2012       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2013         {
2014           real_requested_width = column->fixed_width;
2015         }
2016       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2017         {
2018           real_requested_width = MAX (column->requested_width, column->button_request);
2019         }
2020       else
2021         {
2022           real_requested_width = column->requested_width;
2023         }
2024
2025       if (column->min_width != -1)
2026         real_requested_width = MAX (real_requested_width, column->min_width);
2027       if (column->max_width != -1)
2028         real_requested_width = MIN (real_requested_width, column->max_width);
2029
2030       tree_view->priv->width += real_requested_width;
2031     }
2032
2033   if (tree_view->priv->tree == NULL)
2034     tree_view->priv->height = 0;
2035   else
2036     tree_view->priv->height = tree_view->priv->tree->root->offset;
2037 }
2038
2039 static void
2040 gtk_tree_view_size_request (GtkWidget      *widget,
2041                             GtkRequisition *requisition)
2042 {
2043   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2044   GList *tmp_list;
2045
2046   /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
2047    * sure we have some size. In practice, with a lot of static lists, this
2048    * should get a good width.
2049    */
2050   do_validate_rows (tree_view, FALSE);
2051   gtk_tree_view_size_request_columns (tree_view);
2052   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2053
2054   requisition->width = tree_view->priv->width;
2055   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2056
2057   tmp_list = tree_view->priv->children;
2058
2059   while (tmp_list)
2060     {
2061       GtkTreeViewChild *child = tmp_list->data;
2062       GtkRequisition child_requisition;
2063
2064       tmp_list = tmp_list->next;
2065
2066       if (GTK_WIDGET_VISIBLE (child->widget))
2067         gtk_widget_size_request (child->widget, &child_requisition);
2068     }
2069 }
2070
2071
2072 static void
2073 invalidate_column (GtkTreeView       *tree_view,
2074                    GtkTreeViewColumn *column)
2075 {
2076   gint column_offset = 0;
2077   GList *list;
2078   GtkWidget *widget = GTK_WIDGET (tree_view);
2079   gboolean rtl;
2080
2081   if (!GTK_WIDGET_REALIZED (widget))
2082     return;
2083
2084   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2085   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2086        list;
2087        list = (rtl ? list->prev : list->next))
2088     {
2089       GtkTreeViewColumn *tmpcolumn = list->data;
2090       if (tmpcolumn == column)
2091         {
2092           GdkRectangle invalid_rect;
2093           
2094           invalid_rect.x = column_offset;
2095           invalid_rect.y = 0;
2096           invalid_rect.width = column->width;
2097           invalid_rect.height = widget->allocation.height;
2098           
2099           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2100           break;
2101         }
2102       
2103       column_offset += tmpcolumn->width;
2104     }
2105 }
2106
2107 static void
2108 invalidate_last_column (GtkTreeView *tree_view)
2109 {
2110   GList *last_column;
2111   gboolean rtl;
2112
2113   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2114
2115   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2116        last_column;
2117        last_column = (rtl ? last_column->next : last_column->prev))
2118     {
2119       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2120         {
2121           invalidate_column (tree_view, last_column->data);
2122           return;
2123         }
2124     }
2125 }
2126
2127 static gint
2128 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2129                                                     GtkTreeViewColumn *column)
2130 {
2131   gint real_requested_width;
2132
2133   if (column->use_resized_width)
2134     {
2135       real_requested_width = column->resized_width;
2136     }
2137   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2138     {
2139       real_requested_width = column->fixed_width;
2140     }
2141   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2142     {
2143       real_requested_width = MAX (column->requested_width, column->button_request);
2144     }
2145   else
2146     {
2147       real_requested_width = column->requested_width;
2148       if (real_requested_width < 0)
2149         real_requested_width = 0;
2150     }
2151
2152   if (column->min_width != -1)
2153     real_requested_width = MAX (real_requested_width, column->min_width);
2154   if (column->max_width != -1)
2155     real_requested_width = MIN (real_requested_width, column->max_width);
2156
2157   return real_requested_width;
2158 }
2159
2160 /* GtkWidget::size_allocate helper */
2161 static void
2162 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2163                                      gboolean  *width_changed)
2164 {
2165   GtkTreeView *tree_view;
2166   GList *list, *first_column, *last_column;
2167   GtkTreeViewColumn *column;
2168   GtkAllocation allocation;
2169   gint width = 0;
2170   gint extra, extra_per_column, extra_for_last;
2171   gint full_requested_width = 0;
2172   gint number_of_expand_columns = 0;
2173   gboolean column_changed = FALSE;
2174   gboolean rtl;
2175   gboolean update_expand;
2176   
2177   tree_view = GTK_TREE_VIEW (widget);
2178
2179   for (last_column = g_list_last (tree_view->priv->columns);
2180        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2181        last_column = last_column->prev)
2182     ;
2183   if (last_column == NULL)
2184     return;
2185
2186   for (first_column = g_list_first (tree_view->priv->columns);
2187        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2188        first_column = first_column->next)
2189     ;
2190
2191   allocation.y = 0;
2192   allocation.height = tree_view->priv->header_height;
2193
2194   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2195
2196   /* find out how many extra space and expandable columns we have */
2197   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2198     {
2199       column = (GtkTreeViewColumn *)list->data;
2200
2201       if (!column->visible)
2202         continue;
2203
2204       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2205
2206       if (column->expand)
2207         number_of_expand_columns++;
2208     }
2209
2210   /* Only update the expand value if the width of the widget has changed,
2211    * or the number of expand columns has changed, or if there are no expand
2212    * columns, or if we didn't have an size-allocation yet after the
2213    * last validated node.
2214    */
2215   update_expand = (width_changed && *width_changed == TRUE)
2216       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2217       || number_of_expand_columns == 0
2218       || tree_view->priv->post_validation_flag == TRUE;
2219
2220   tree_view->priv->post_validation_flag = FALSE;
2221
2222   if (!update_expand)
2223     {
2224       extra = tree_view->priv->last_extra_space;
2225       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2226     }
2227   else
2228     {
2229       extra = MAX (widget->allocation.width - full_requested_width, 0);
2230       extra_for_last = 0;
2231
2232       tree_view->priv->last_extra_space = extra;
2233     }
2234
2235   if (number_of_expand_columns > 0)
2236     extra_per_column = extra/number_of_expand_columns;
2237   else
2238     extra_per_column = 0;
2239
2240   if (update_expand)
2241     {
2242       tree_view->priv->last_extra_space_per_column = extra_per_column;
2243       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2244     }
2245
2246   for (list = (rtl ? last_column : first_column); 
2247        list != (rtl ? first_column->prev : last_column->next);
2248        list = (rtl ? list->prev : list->next)) 
2249     {
2250       gint real_requested_width = 0;
2251       gint old_width;
2252
2253       column = list->data;
2254       old_width = column->width;
2255
2256       if (!column->visible)
2257         continue;
2258
2259       /* We need to handle the dragged button specially.
2260        */
2261       if (column == tree_view->priv->drag_column)
2262         {
2263           GtkAllocation drag_allocation;
2264           gdk_drawable_get_size (tree_view->priv->drag_window,
2265                                  &(drag_allocation.width),
2266                                  &(drag_allocation.height));
2267           drag_allocation.x = 0;
2268           drag_allocation.y = 0;
2269           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2270                                     &drag_allocation);
2271           width += drag_allocation.width;
2272           continue;
2273         }
2274
2275       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2276
2277       allocation.x = width;
2278       column->width = real_requested_width;
2279
2280       if (column->expand)
2281         {
2282           if (number_of_expand_columns == 1)
2283             {
2284               /* We add the remander to the last column as
2285                * */
2286               column->width += extra;
2287             }
2288           else
2289             {
2290               column->width += extra_per_column;
2291               extra -= extra_per_column;
2292               number_of_expand_columns --;
2293             }
2294         }
2295       else if (number_of_expand_columns == 0 &&
2296                list == last_column)
2297         {
2298           column->width += extra;
2299         }
2300
2301       /* In addition to expand, the last column can get even more
2302        * extra space so all available space is filled up.
2303        */
2304       if (extra_for_last > 0 && list == last_column)
2305         column->width += extra_for_last;
2306
2307       g_object_notify (G_OBJECT (column), "width");
2308
2309       allocation.width = column->width;
2310       width += column->width;
2311
2312       if (column->width > old_width)
2313         column_changed = TRUE;
2314
2315       gtk_widget_size_allocate (column->button, &allocation);
2316
2317       if (column->window)
2318         gdk_window_move_resize (column->window,
2319                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2320                                 allocation.y,
2321                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2322     }
2323
2324   /* We change the width here.  The user might have been resizing columns,
2325    * so the total width of the tree view changes.
2326    */
2327   tree_view->priv->width = width;
2328   if (width_changed)
2329     *width_changed = TRUE;
2330
2331   if (column_changed)
2332     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2333 }
2334
2335
2336 static void
2337 gtk_tree_view_size_allocate (GtkWidget     *widget,
2338                              GtkAllocation *allocation)
2339 {
2340   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2341   GList *tmp_list;
2342   gboolean width_changed = FALSE;
2343   gint old_width = widget->allocation.width;
2344
2345   if (allocation->width != widget->allocation.width)
2346     width_changed = TRUE;
2347
2348   widget->allocation = *allocation;
2349
2350   tmp_list = tree_view->priv->children;
2351
2352   while (tmp_list)
2353     {
2354       GtkAllocation allocation;
2355
2356       GtkTreeViewChild *child = tmp_list->data;
2357       tmp_list = tmp_list->next;
2358
2359       /* totally ignore our child's requisition */
2360       allocation.x = child->x;
2361       allocation.y = child->y;
2362       allocation.width = child->width;
2363       allocation.height = child->height;
2364       gtk_widget_size_allocate (child->widget, &allocation);
2365     }
2366
2367   /* We size-allocate the columns first because the width of the
2368    * tree view (used in updating the adjustments below) might change.
2369    */
2370   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2371
2372   tree_view->priv->hadjustment->page_size = allocation->width;
2373   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2374   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2375   tree_view->priv->hadjustment->lower = 0;
2376   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2377
2378   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2379     {
2380       if (allocation->width < tree_view->priv->width)
2381         {
2382           if (tree_view->priv->init_hadjust_value)
2383             {
2384               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2385               tree_view->priv->init_hadjust_value = FALSE;
2386             }
2387           else if (allocation->width != old_width)
2388             {
2389               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2390             }
2391           else
2392             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);
2393         }
2394       else
2395         {
2396           tree_view->priv->hadjustment->value = 0;
2397           tree_view->priv->init_hadjust_value = TRUE;
2398         }
2399     }
2400   else
2401     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2402       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2403
2404   gtk_adjustment_changed (tree_view->priv->hadjustment);
2405
2406   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2407   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2408   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2409   tree_view->priv->vadjustment->lower = 0;
2410   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2411
2412   gtk_adjustment_changed (tree_view->priv->vadjustment);
2413
2414   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2415   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2416     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2417   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2418     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2419                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2420   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2421     gtk_tree_view_top_row_to_dy (tree_view);
2422   else
2423     gtk_tree_view_dy_to_top_row (tree_view);
2424   
2425   if (GTK_WIDGET_REALIZED (widget))
2426     {
2427       gdk_window_move_resize (widget->window,
2428                               allocation->x, allocation->y,
2429                               allocation->width, allocation->height);
2430       gdk_window_move_resize (tree_view->priv->header_window,
2431                               - (gint) tree_view->priv->hadjustment->value,
2432                               0,
2433                               MAX (tree_view->priv->width, allocation->width),
2434                               tree_view->priv->header_height);
2435       gdk_window_move_resize (tree_view->priv->bin_window,
2436                               - (gint) tree_view->priv->hadjustment->value,
2437                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2438                               MAX (tree_view->priv->width, allocation->width),
2439                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2440     }
2441
2442   if (tree_view->priv->tree == NULL)
2443     invalidate_empty_focus (tree_view);
2444
2445   if (GTK_WIDGET_REALIZED (widget))
2446     {
2447       gboolean has_expand_column = FALSE;
2448       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2449         {
2450           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2451             {
2452               has_expand_column = TRUE;
2453               break;
2454             }
2455         }
2456
2457       /* This little hack only works if we have an LTR locale, and no column has the  */
2458       if (width_changed)
2459         {
2460           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2461               ! has_expand_column)
2462             invalidate_last_column (tree_view);
2463           else
2464             gtk_widget_queue_draw (widget);
2465         }
2466     }
2467 }
2468
2469 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2470 static void
2471 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2472 {
2473   if (GTK_WIDGET_CAN_FOCUS (tree_view) && !GTK_WIDGET_HAS_FOCUS (tree_view))
2474     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2475   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2476 }
2477
2478 static inline gboolean
2479 row_is_separator (GtkTreeView *tree_view,
2480                   GtkTreeIter *iter,
2481                   GtkTreePath *path)
2482 {
2483   gboolean is_separator = FALSE;
2484
2485   if (tree_view->priv->row_separator_func)
2486     {
2487       GtkTreeIter tmpiter;
2488
2489       if (iter)
2490         tmpiter = *iter;
2491       else
2492         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2493
2494       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2495                                                           &tmpiter,
2496                                                           tree_view->priv->row_separator_data);
2497     }
2498
2499   return is_separator;
2500 }
2501
2502 static gboolean
2503 gtk_tree_view_button_press (GtkWidget      *widget,
2504                             GdkEventButton *event)
2505 {
2506   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2507   GList *list;
2508   GtkTreeViewColumn *column = NULL;
2509   gint i;
2510   GdkRectangle background_area;
2511   GdkRectangle cell_area;
2512   gint vertical_separator;
2513   gint horizontal_separator;
2514   gboolean path_is_selectable;
2515   gboolean rtl;
2516
2517   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2518   gtk_tree_view_stop_editing (tree_view, FALSE);
2519   gtk_widget_style_get (widget,
2520                         "vertical-separator", &vertical_separator,
2521                         "horizontal-separator", &horizontal_separator,
2522                         NULL);
2523
2524
2525   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2526    * we're done handling the button press.
2527    */
2528
2529   if (event->window == tree_view->priv->bin_window)
2530     {
2531       GtkRBNode *node;
2532       GtkRBTree *tree;
2533       GtkTreePath *path;
2534       gchar *path_string;
2535       gint depth;
2536       gint new_y;
2537       gint y_offset;
2538       gint dval;
2539       gint pre_val, aft_val;
2540       GtkTreeViewColumn *column = NULL;
2541       GtkCellRenderer *focus_cell = NULL;
2542       gint column_handled_click = FALSE;
2543       gboolean row_double_click = FALSE;
2544       gboolean rtl;
2545       gboolean node_selected;
2546
2547       /* Empty tree? */
2548       if (tree_view->priv->tree == NULL)
2549         {
2550           grab_focus_and_unset_draw_keyfocus (tree_view);
2551           return TRUE;
2552         }
2553
2554       /* are we in an arrow? */
2555       if (tree_view->priv->prelight_node &&
2556           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2557           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2558         {
2559           if (event->button == 1)
2560             {
2561               gtk_grab_add (widget);
2562               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2563               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2564               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2565                                         tree_view->priv->prelight_tree,
2566                                         tree_view->priv->prelight_node,
2567                                         event->x,
2568                                         event->y);
2569             }
2570
2571           grab_focus_and_unset_draw_keyfocus (tree_view);
2572           return TRUE;
2573         }
2574
2575       /* find the node that was clicked */
2576       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2577       if (new_y < 0)
2578         new_y = 0;
2579       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2580
2581       if (node == NULL)
2582         {
2583           /* We clicked in dead space */
2584           grab_focus_and_unset_draw_keyfocus (tree_view);
2585           return TRUE;
2586         }
2587
2588       /* Get the path and the node */
2589       path = _gtk_tree_view_find_path (tree_view, tree, node);
2590       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2591
2592       if (!path_is_selectable)
2593         {
2594           gtk_tree_path_free (path);
2595           grab_focus_and_unset_draw_keyfocus (tree_view);
2596           return TRUE;
2597         }
2598
2599       depth = gtk_tree_path_get_depth (path);
2600       background_area.y = y_offset + event->y;
2601       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2602       background_area.x = 0;
2603
2604
2605       /* Let the column have a chance at selecting it. */
2606       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2607       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2608            list; list = (rtl ? list->prev : list->next))
2609         {
2610           GtkTreeViewColumn *candidate = list->data;
2611
2612           if (!candidate->visible)
2613             continue;
2614
2615           background_area.width = candidate->width;
2616           if ((background_area.x > (gint) event->x) ||
2617               (background_area.x + background_area.width <= (gint) event->x))
2618             {
2619               background_area.x += background_area.width;
2620               continue;
2621             }
2622
2623           /* we found the focus column */
2624           column = candidate;
2625           cell_area = background_area;
2626           cell_area.width -= horizontal_separator;
2627           cell_area.height -= vertical_separator;
2628           cell_area.x += horizontal_separator/2;
2629           cell_area.y += vertical_separator/2;
2630           if (gtk_tree_view_is_expander_column (tree_view, column))
2631             {
2632               if (!rtl)
2633                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2634               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2635
2636               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2637                 {
2638                   if (!rtl)
2639                     cell_area.x += depth * tree_view->priv->expander_size;
2640                   cell_area.width -= depth * tree_view->priv->expander_size;
2641                 }
2642             }
2643           break;
2644         }
2645
2646       if (column == NULL)
2647         {
2648           gtk_tree_path_free (path);
2649           grab_focus_and_unset_draw_keyfocus (tree_view);
2650           return FALSE;
2651         }
2652
2653       tree_view->priv->focus_column = column;
2654
2655       /* decide if we edit */
2656       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2657           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2658         {
2659           GtkTreePath *anchor;
2660           GtkTreeIter iter;
2661
2662           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2663           gtk_tree_view_column_cell_set_cell_data (column,
2664                                                    tree_view->priv->model,
2665                                                    &iter,
2666                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2667                                                    node->children?TRUE:FALSE);
2668
2669           if (tree_view->priv->anchor)
2670             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2671           else
2672             anchor = NULL;
2673
2674           if ((anchor && !gtk_tree_path_compare (anchor, path))
2675               || !_gtk_tree_view_column_has_editable_cell (column))
2676             {
2677               GtkCellEditable *cell_editable = NULL;
2678
2679               /* FIXME: get the right flags */
2680               guint flags = 0;
2681
2682               path_string = gtk_tree_path_to_string (path);
2683
2684               if (_gtk_tree_view_column_cell_event (column,
2685                                                     &cell_editable,
2686                                                     (GdkEvent *)event,
2687                                                     path_string,
2688                                                     &background_area,
2689                                                     &cell_area, flags))
2690                 {
2691                   if (cell_editable != NULL)
2692                     {
2693                       gint left, right;
2694                       GdkRectangle area;
2695
2696                       area = cell_area;
2697                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2698
2699                       area.x += left;
2700                       area.width -= right + left;
2701
2702                       gtk_tree_view_real_start_editing (tree_view,
2703                                                         column,
2704                                                         path,
2705                                                         cell_editable,
2706                                                         &area,
2707                                                         (GdkEvent *)event,
2708                                                         flags);
2709                       g_free (path_string);
2710                       gtk_tree_path_free (path);
2711                       gtk_tree_path_free (anchor);
2712                       return TRUE;
2713                     }
2714                   column_handled_click = TRUE;
2715                 }
2716               g_free (path_string);
2717             }
2718           if (anchor)
2719             gtk_tree_path_free (anchor);
2720         }
2721
2722       /* select */
2723       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2724       pre_val = tree_view->priv->vadjustment->value;
2725
2726       /* we only handle selection modifications on the first button press
2727        */
2728       if (event->type == GDK_BUTTON_PRESS)
2729         {
2730           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2731             tree_view->priv->ctrl_pressed = TRUE;
2732           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2733             tree_view->priv->shift_pressed = TRUE;
2734
2735           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2736           if (focus_cell)
2737             gtk_tree_view_column_focus_cell (column, focus_cell);
2738
2739           if (event->state & GDK_CONTROL_MASK)
2740             {
2741               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2742               gtk_tree_view_real_toggle_cursor_row (tree_view);
2743             }
2744           else if (event->state & GDK_SHIFT_MASK)
2745             {
2746               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2747               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2748             }
2749           else
2750             {
2751               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2752             }
2753
2754           tree_view->priv->ctrl_pressed = FALSE;
2755           tree_view->priv->shift_pressed = FALSE;
2756         }
2757
2758       /* the treeview may have been scrolled because of _set_cursor,
2759        * correct here
2760        */
2761
2762       aft_val = tree_view->priv->vadjustment->value;
2763       dval = pre_val - aft_val;
2764
2765       cell_area.y += dval;
2766       background_area.y += dval;
2767
2768       /* Save press to possibly begin a drag
2769        */
2770       if (!column_handled_click &&
2771           !tree_view->priv->in_grab &&
2772           tree_view->priv->pressed_button < 0)
2773         {
2774           tree_view->priv->pressed_button = event->button;
2775           tree_view->priv->press_start_x = event->x;
2776           tree_view->priv->press_start_y = event->y;
2777
2778           if (tree_view->priv->rubber_banding_enable
2779               && !node_selected
2780               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2781             {
2782               tree_view->priv->press_start_y += tree_view->priv->dy;
2783               tree_view->priv->rubber_band_x = event->x;
2784               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2785               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2786
2787               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2788                 tree_view->priv->rubber_band_ctrl = TRUE;
2789               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2790                 tree_view->priv->rubber_band_shift = TRUE;
2791             }
2792         }
2793
2794       /* Test if a double click happened on the same row. */
2795       if (event->button == 1)
2796         {
2797           /* We also handle triple clicks here, because a user could have done
2798            * a first click and a second double click on different rows.
2799            */
2800           if ((event->type == GDK_2BUTTON_PRESS
2801                || event->type == GDK_3BUTTON_PRESS)
2802               && tree_view->priv->last_button_press)
2803             {
2804               GtkTreePath *lsc;
2805
2806               lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
2807
2808               if (lsc)
2809                 {
2810                   row_double_click = !gtk_tree_path_compare (lsc, path);
2811                   gtk_tree_path_free (lsc);
2812                 }
2813             }
2814
2815           if (row_double_click)
2816             {
2817               if (tree_view->priv->last_button_press)
2818                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2819               if (tree_view->priv->last_button_press_2)
2820                 gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
2821               tree_view->priv->last_button_press = NULL;
2822               tree_view->priv->last_button_press_2 = NULL;
2823             }
2824           else
2825             {
2826               if (tree_view->priv->last_button_press)
2827                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2828               tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
2829               tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
2830             }
2831         }
2832
2833       if (row_double_click)
2834         {
2835           gtk_grab_remove (widget);
2836           gtk_tree_view_row_activated (tree_view, path, column);
2837
2838           if (tree_view->priv->pressed_button == event->button)
2839             tree_view->priv->pressed_button = -1;
2840         }
2841
2842       gtk_tree_path_free (path);
2843
2844       /* If we activated the row through a double click we don't want to grab
2845        * focus back, as moving focus to another widget is pretty common.
2846        */
2847       if (!row_double_click)
2848         grab_focus_and_unset_draw_keyfocus (tree_view);
2849
2850       return TRUE;
2851     }
2852
2853   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2854    */
2855   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2856     {
2857       column = list->data;
2858       if (event->window == column->window &&
2859           column->resizable &&
2860           column->window)
2861         {
2862           gpointer drag_data;
2863
2864           if (event->type == GDK_2BUTTON_PRESS &&
2865               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2866             {
2867               column->use_resized_width = FALSE;
2868               _gtk_tree_view_column_autosize (tree_view, column);
2869               return TRUE;
2870             }
2871
2872           if (gdk_pointer_grab (column->window, FALSE,
2873                                 GDK_POINTER_MOTION_HINT_MASK |
2874                                 GDK_BUTTON1_MOTION_MASK |
2875                                 GDK_BUTTON_RELEASE_MASK,
2876                                 NULL, NULL, event->time))
2877             return FALSE;
2878
2879           gtk_grab_add (widget);
2880           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2881           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2882
2883           /* block attached dnd signal handler */
2884           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2885           if (drag_data)
2886             g_signal_handlers_block_matched (widget,
2887                                              G_SIGNAL_MATCH_DATA,
2888                                              0, 0, NULL, NULL,
2889                                              drag_data);
2890
2891           tree_view->priv->drag_pos = i;
2892           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2893
2894           if (!GTK_WIDGET_HAS_FOCUS (widget))
2895             gtk_widget_grab_focus (widget);
2896
2897           return TRUE;
2898         }
2899     }
2900   return FALSE;
2901 }
2902
2903 /* GtkWidget::button_release_event helper */
2904 static gboolean
2905 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2906                                           GdkEventButton *event)
2907 {
2908   GtkTreeView *tree_view;
2909   GList *l;
2910   gboolean rtl;
2911
2912   tree_view = GTK_TREE_VIEW (widget);
2913
2914   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2915   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2916   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2917
2918   /* Move the button back */
2919   g_object_ref (tree_view->priv->drag_column->button);
2920   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2921   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2922   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2923   g_object_unref (tree_view->priv->drag_column->button);
2924   gtk_widget_queue_resize (widget);
2925   if (tree_view->priv->drag_column->resizable)
2926     {
2927       gdk_window_raise (tree_view->priv->drag_column->window);
2928       gdk_window_show (tree_view->priv->drag_column->window);
2929     }
2930   else
2931     gdk_window_hide (tree_view->priv->drag_column->window);
2932
2933   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2934
2935   if (rtl)
2936     {
2937       if (tree_view->priv->cur_reorder &&
2938           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2939         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2940                                          tree_view->priv->cur_reorder->right_column);
2941     }
2942   else
2943     {
2944       if (tree_view->priv->cur_reorder &&
2945           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2946         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2947                                          tree_view->priv->cur_reorder->left_column);
2948     }
2949   tree_view->priv->drag_column = NULL;
2950   gdk_window_hide (tree_view->priv->drag_window);
2951
2952   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2953     g_slice_free (GtkTreeViewColumnReorder, l->data);
2954   g_list_free (tree_view->priv->column_drag_info);
2955   tree_view->priv->column_drag_info = NULL;
2956   tree_view->priv->cur_reorder = NULL;
2957
2958   if (tree_view->priv->drag_highlight_window)
2959     gdk_window_hide (tree_view->priv->drag_highlight_window);
2960
2961   /* Reset our flags */
2962   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2963   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2964
2965   return TRUE;
2966 }
2967
2968 /* GtkWidget::button_release_event helper */
2969 static gboolean
2970 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2971                                             GdkEventButton *event)
2972 {
2973   GtkTreeView *tree_view;
2974   gpointer drag_data;
2975
2976   tree_view = GTK_TREE_VIEW (widget);
2977
2978   tree_view->priv->drag_pos = -1;
2979
2980   /* unblock attached dnd signal handler */
2981   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2982   if (drag_data)
2983     g_signal_handlers_unblock_matched (widget,
2984                                        G_SIGNAL_MATCH_DATA,
2985                                        0, 0, NULL, NULL,
2986                                        drag_data);
2987
2988   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2989   gtk_grab_remove (widget);
2990   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
2991                               event->time);
2992   return TRUE;
2993 }
2994
2995 static gboolean
2996 gtk_tree_view_button_release (GtkWidget      *widget,
2997                               GdkEventButton *event)
2998 {
2999   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3000
3001   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3002     return gtk_tree_view_button_release_drag_column (widget, event);
3003
3004   if (tree_view->priv->rubber_band_status)
3005     gtk_tree_view_stop_rubber_band (tree_view);
3006
3007   if (tree_view->priv->pressed_button == event->button)
3008     tree_view->priv->pressed_button = -1;
3009
3010   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3011     return gtk_tree_view_button_release_column_resize (widget, event);
3012
3013   if (tree_view->priv->button_pressed_node == NULL)
3014     return FALSE;
3015
3016   if (event->button == 1)
3017     {
3018       gtk_grab_remove (widget);
3019       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3020           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3021         {
3022           GtkTreePath *path = NULL;
3023
3024           path = _gtk_tree_view_find_path (tree_view,
3025                                            tree_view->priv->button_pressed_tree,
3026                                            tree_view->priv->button_pressed_node);
3027           /* Actually activate the node */
3028           if (tree_view->priv->button_pressed_node->children == NULL)
3029             gtk_tree_view_real_expand_row (tree_view, path,
3030                                            tree_view->priv->button_pressed_tree,
3031                                            tree_view->priv->button_pressed_node,
3032                                            FALSE, TRUE);
3033           else
3034             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3035                                              tree_view->priv->button_pressed_tree,
3036                                              tree_view->priv->button_pressed_node, TRUE);
3037           gtk_tree_path_free (path);
3038         }
3039
3040       tree_view->priv->button_pressed_tree = NULL;
3041       tree_view->priv->button_pressed_node = NULL;
3042     }
3043
3044   return TRUE;
3045 }
3046
3047 static gboolean
3048 gtk_tree_view_grab_broken (GtkWidget          *widget,
3049                            GdkEventGrabBroken *event)
3050 {
3051   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3052
3053   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3054     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3055
3056   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3057     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3058
3059   return TRUE;
3060 }
3061
3062 #if 0
3063 static gboolean
3064 gtk_tree_view_configure (GtkWidget *widget,
3065                          GdkEventConfigure *event)
3066 {
3067   GtkTreeView *tree_view;
3068
3069   tree_view = GTK_TREE_VIEW (widget);
3070   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3071
3072   return FALSE;
3073 }
3074 #endif
3075
3076 /* GtkWidget::motion_event function set.
3077  */
3078
3079 static gboolean
3080 coords_are_over_arrow (GtkTreeView *tree_view,
3081                        GtkRBTree   *tree,
3082                        GtkRBNode   *node,
3083                        /* these are in bin window coords */
3084                        gint         x,
3085                        gint         y)
3086 {
3087   GdkRectangle arrow;
3088   gint x2;
3089
3090   if (!GTK_WIDGET_REALIZED (tree_view))
3091     return FALSE;
3092
3093   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3094     return FALSE;
3095
3096   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3097
3098   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3099
3100   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3101
3102   arrow.width = x2 - arrow.x;
3103
3104   return (x >= arrow.x &&
3105           x < (arrow.x + arrow.width) &&
3106           y >= arrow.y &&
3107           y < (arrow.y + arrow.height));
3108 }
3109
3110 static gboolean
3111 auto_expand_timeout (gpointer data)
3112 {
3113   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3114   GtkTreePath *path;
3115
3116   if (tree_view->priv->prelight_node)
3117     {
3118       path = _gtk_tree_view_find_path (tree_view,
3119                                        tree_view->priv->prelight_tree,
3120                                        tree_view->priv->prelight_node);   
3121
3122       if (tree_view->priv->prelight_node->children)
3123         gtk_tree_view_collapse_row (tree_view, path);
3124       else
3125         gtk_tree_view_expand_row (tree_view, path, FALSE);
3126
3127       gtk_tree_path_free (path);
3128     }
3129
3130   tree_view->priv->auto_expand_timeout = 0;
3131
3132   return FALSE;
3133 }
3134
3135 static void
3136 remove_auto_expand_timeout (GtkTreeView *tree_view)
3137 {
3138   if (tree_view->priv->auto_expand_timeout != 0)
3139     {
3140       g_source_remove (tree_view->priv->auto_expand_timeout);
3141       tree_view->priv->auto_expand_timeout = 0;
3142     }
3143 }
3144
3145 static void
3146 do_prelight (GtkTreeView *tree_view,
3147              GtkRBTree   *tree,
3148              GtkRBNode   *node,
3149              /* these are in bin_window coords */
3150              gint         x,
3151              gint         y)
3152 {
3153   if (tree_view->priv->prelight_tree == tree &&
3154       tree_view->priv->prelight_node == node)
3155     {
3156       /*  We are still on the same node,
3157           but we might need to take care of the arrow  */
3158
3159       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3160         {
3161           gboolean over_arrow;
3162           gboolean flag_set;
3163
3164           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3165           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3166                                              GTK_TREE_VIEW_ARROW_PRELIT);
3167
3168           if (over_arrow != flag_set)
3169             {
3170               if (over_arrow)
3171                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3172                                         GTK_TREE_VIEW_ARROW_PRELIT);
3173               else
3174                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3175                                           GTK_TREE_VIEW_ARROW_PRELIT);
3176
3177               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3178             }
3179         }
3180
3181       return;
3182     }
3183
3184   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3185     {
3186       /*  Unprelight the old node and arrow  */
3187
3188       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3189                              GTK_RBNODE_IS_PRELIT);
3190
3191       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3192           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3193         {
3194           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3195           
3196           gtk_tree_view_draw_arrow (tree_view,
3197                                     tree_view->priv->prelight_tree,
3198                                     tree_view->priv->prelight_node,
3199                                     x,
3200                                     y);
3201         }
3202
3203       _gtk_tree_view_queue_draw_node (tree_view,
3204                                       tree_view->priv->prelight_tree,
3205                                       tree_view->priv->prelight_node,
3206                                       NULL);
3207     }
3208
3209
3210   if (tree_view->priv->hover_expand)
3211     remove_auto_expand_timeout (tree_view);
3212
3213   /*  Set the new prelight values  */
3214   tree_view->priv->prelight_node = node;
3215   tree_view->priv->prelight_tree = tree;
3216
3217   if (!node || !tree)
3218     return;
3219
3220   /*  Prelight the new node and arrow  */
3221
3222   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3223       && coords_are_over_arrow (tree_view, tree, node, x, y))
3224     {
3225       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3226
3227       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3228     }
3229
3230   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3231
3232   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3233
3234   if (tree_view->priv->hover_expand)
3235     {
3236       tree_view->priv->auto_expand_timeout = 
3237         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3238     }
3239 }
3240
3241 static void
3242 prelight_or_select (GtkTreeView *tree_view,
3243                     GtkRBTree   *tree,
3244                     GtkRBNode   *node,
3245                     /* these are in bin_window coords */
3246                     gint         x,
3247                     gint         y)
3248 {
3249   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3250   
3251   if (tree_view->priv->hover_selection &&
3252       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3253       !(tree_view->priv->edited_column &&
3254         tree_view->priv->edited_column->editable_widget))
3255     {
3256       if (node)
3257         {
3258           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3259             {
3260               GtkTreePath *path;
3261               
3262               path = _gtk_tree_view_find_path (tree_view, tree, node);
3263               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3264               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3265                 {
3266                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3267                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3268                 }
3269               gtk_tree_path_free (path);
3270             }
3271         }
3272
3273       else if (mode == GTK_SELECTION_SINGLE)
3274         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3275     }
3276
3277     do_prelight (tree_view, tree, node, x, y);
3278 }
3279
3280 static void
3281 ensure_unprelighted (GtkTreeView *tree_view)
3282 {
3283   do_prelight (tree_view,
3284                NULL, NULL,
3285                -1000, -1000); /* coords not possibly over an arrow */
3286
3287   g_assert (tree_view->priv->prelight_node == NULL);
3288 }
3289
3290
3291
3292
3293 /* Our motion arrow is either a box (in the case of the original spot)
3294  * or an arrow.  It is expander_size wide.
3295  */
3296 /*
3297  * 11111111111111
3298  * 01111111111110
3299  * 00111111111100
3300  * 00011111111000
3301  * 00001111110000
3302  * 00000111100000
3303  * 00000111100000
3304  * 00000111100000
3305  * ~ ~ ~ ~ ~ ~ ~
3306  * 00000111100000
3307  * 00000111100000
3308  * 00000111100000
3309  * 00001111110000
3310  * 00011111111000
3311  * 00111111111100
3312  * 01111111111110
3313  * 11111111111111
3314  */
3315
3316 static void
3317 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3318 {
3319   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3320   GtkWidget *widget = GTK_WIDGET (tree_view);
3321   GdkBitmap *mask = NULL;
3322   gint x;
3323   gint y;
3324   gint width;
3325   gint height;
3326   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3327   GdkWindowAttr attributes;
3328   guint attributes_mask;
3329
3330   if (!reorder ||
3331       reorder->left_column == tree_view->priv->drag_column ||
3332       reorder->right_column == tree_view->priv->drag_column)
3333     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3334   else if (reorder->left_column || reorder->right_column)
3335     {
3336       GdkRectangle visible_rect;
3337       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3338       if (reorder->left_column)
3339         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3340       else
3341         x = reorder->right_column->button->allocation.x;
3342
3343       if (x < visible_rect.x)
3344         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3345       else if (x > visible_rect.x + visible_rect.width)
3346         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3347       else
3348         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3349     }
3350
3351   /* We want to draw the rectangle over the initial location. */
3352   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3353     {
3354       GdkGC *gc;
3355       GdkColor col;
3356
3357       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3358         {
3359           if (tree_view->priv->drag_highlight_window)
3360             {
3361               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3362                                         NULL);
3363               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3364             }
3365
3366           attributes.window_type = GDK_WINDOW_CHILD;
3367           attributes.wclass = GDK_INPUT_OUTPUT;
3368           attributes.x = tree_view->priv->drag_column_x;
3369           attributes.y = 0;
3370           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3371           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3372           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3373           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3374           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3375           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3376           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3377           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3378
3379           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3380           gc = gdk_gc_new (mask);
3381           col.pixel = 1;
3382           gdk_gc_set_foreground (gc, &col);
3383           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3384           col.pixel = 0;
3385           gdk_gc_set_foreground(gc, &col);
3386           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3387           g_object_unref (gc);
3388
3389           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3390                                          mask, 0, 0);
3391           if (mask) g_object_unref (mask);
3392           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3393         }
3394     }
3395   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3396     {
3397       gint i, j = 1;
3398       GdkGC *gc;
3399       GdkColor col;
3400
3401       width = tree_view->priv->expander_size;
3402
3403       /* Get x, y, width, height of arrow */
3404       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3405       if (reorder->left_column)
3406         {
3407           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3408           height = reorder->left_column->button->allocation.height;
3409         }
3410       else
3411         {
3412           x += reorder->right_column->button->allocation.x - width/2;
3413           height = reorder->right_column->button->allocation.height;
3414         }
3415       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3416       height += tree_view->priv->expander_size;
3417
3418       /* Create the new window */
3419       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3420         {
3421           if (tree_view->priv->drag_highlight_window)
3422             {
3423               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3424                                         NULL);
3425               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3426             }
3427
3428           attributes.window_type = GDK_WINDOW_TEMP;
3429           attributes.wclass = GDK_INPUT_OUTPUT;
3430           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3431           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3432           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3433           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3434           attributes.x = x;
3435           attributes.y = y;
3436           attributes.width = width;
3437           attributes.height = height;
3438           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3439                                                                    &attributes, attributes_mask);
3440           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3441
3442           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3443           gc = gdk_gc_new (mask);
3444           col.pixel = 1;
3445           gdk_gc_set_foreground (gc, &col);
3446           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3447
3448           /* Draw the 2 arrows as per above */
3449           col.pixel = 0;
3450           gdk_gc_set_foreground (gc, &col);
3451           for (i = 0; i < width; i ++)
3452             {
3453               if (i == (width/2 - 1))
3454                 continue;
3455               gdk_draw_line (mask, gc, i, j, i, height - j);
3456               if (i < (width/2 - 1))
3457                 j++;
3458               else
3459                 j--;
3460             }
3461           g_object_unref (gc);
3462           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3463                                          mask, 0, 0);
3464           if (mask) g_object_unref (mask);
3465         }
3466
3467       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3468       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3469     }
3470   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3471            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3472     {
3473       gint i, j = 1;
3474       GdkGC *gc;
3475       GdkColor col;
3476
3477       width = tree_view->priv->expander_size;
3478
3479       /* Get x, y, width, height of arrow */
3480       width = width/2; /* remember, the arrow only takes half the available width */
3481       gdk_window_get_origin (widget->window, &x, &y);
3482       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3483         x += widget->allocation.width - width;
3484
3485       if (reorder->left_column)
3486         height = reorder->left_column->button->allocation.height;
3487       else
3488         height = reorder->right_column->button->allocation.height;
3489
3490       y -= tree_view->priv->expander_size;
3491       height += 2*tree_view->priv->expander_size;
3492
3493       /* Create the new window */
3494       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3495           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3496         {
3497           if (tree_view->priv->drag_highlight_window)
3498             {
3499               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3500                                         NULL);
3501               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3502             }
3503
3504           attributes.window_type = GDK_WINDOW_TEMP;
3505           attributes.wclass = GDK_INPUT_OUTPUT;
3506           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3507           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3508           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3509           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3510           attributes.x = x;
3511           attributes.y = y;
3512           attributes.width = width;
3513           attributes.height = height;
3514           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3515           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3516
3517           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3518           gc = gdk_gc_new (mask);
3519           col.pixel = 1;
3520           gdk_gc_set_foreground (gc, &col);
3521           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3522
3523           /* Draw the 2 arrows as per above */
3524           col.pixel = 0;
3525           gdk_gc_set_foreground (gc, &col);
3526           j = tree_view->priv->expander_size;
3527           for (i = 0; i < width; i ++)
3528             {
3529               gint k;
3530               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3531                 k = width - i - 1;
3532               else
3533                 k = i;
3534               gdk_draw_line (mask, gc, k, j, k, height - j);
3535               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3536               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3537               j--;
3538             }
3539           g_object_unref (gc);
3540           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3541                                          mask, 0, 0);
3542           if (mask) g_object_unref (mask);
3543         }
3544
3545       tree_view->priv->drag_column_window_state = arrow_type;
3546       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3547    }
3548   else
3549     {
3550       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3551       gdk_window_hide (tree_view->priv->drag_highlight_window);
3552       return;
3553     }
3554
3555   gdk_window_show (tree_view->priv->drag_highlight_window);
3556   gdk_window_raise (tree_view->priv->drag_highlight_window);
3557 }
3558
3559 static gboolean
3560 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3561                                     GdkEventMotion *event)
3562 {
3563   gint x;
3564   gint new_width;
3565   GtkTreeViewColumn *column;
3566   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3567
3568   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3569
3570   if (event->is_hint || event->window != widget->window)
3571     gtk_widget_get_pointer (widget, &x, NULL);
3572   else
3573     x = event->x;
3574
3575   if (tree_view->priv->hadjustment)
3576     x += tree_view->priv->hadjustment->value;
3577
3578   new_width = gtk_tree_view_new_column_width (tree_view,
3579                                               tree_view->priv->drag_pos, &x);
3580   if (x != tree_view->priv->x_drag &&
3581       (new_width != column->fixed_width))
3582     {
3583       column->use_resized_width = TRUE;
3584       column->resized_width = new_width;
3585       if (column->expand)
3586         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3587       gtk_widget_queue_resize (widget);
3588     }
3589
3590   return FALSE;
3591 }
3592
3593
3594 static void
3595 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3596 {
3597   GtkTreeViewColumnReorder *reorder = NULL;
3598   GList *list;
3599   gint mouse_x;
3600
3601   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3602   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3603     {
3604       reorder = (GtkTreeViewColumnReorder *) list->data;
3605       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3606         break;
3607       reorder = NULL;
3608     }
3609
3610   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3611       return;*/
3612
3613   tree_view->priv->cur_reorder = reorder;
3614   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3615 }
3616
3617 static void
3618 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3619 {
3620   GdkRectangle visible_rect;
3621   gint y;
3622   gint offset;
3623   gfloat value;
3624
3625   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3626   y += tree_view->priv->dy;
3627
3628   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3629
3630   /* see if we are near the edge. */
3631   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3632   if (offset > 0)
3633     {
3634       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3635       if (offset < 0)
3636         return;
3637     }
3638
3639   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
3640                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
3641   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
3642 }
3643
3644 static gboolean
3645 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3646 {
3647   GdkRectangle visible_rect;
3648   gint x;
3649   gint offset;
3650   gfloat value;
3651
3652   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3653
3654   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3655
3656   /* See if we are near the edge. */
3657   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3658   if (offset > 0)
3659     {
3660       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3661       if (offset < 0)
3662         return TRUE;
3663     }
3664   offset = offset/3;
3665
3666   value = CLAMP (tree_view->priv->hadjustment->value + offset,
3667                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
3668   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
3669
3670   return TRUE;
3671
3672 }
3673
3674 static gboolean
3675 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3676                                   GdkEventMotion *event)
3677 {
3678   GtkTreeView *tree_view = (GtkTreeView *) widget;
3679   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3680   gint x, y;
3681
3682   /* Sanity Check */
3683   if ((column == NULL) ||
3684       (event->window != tree_view->priv->drag_window))
3685     return FALSE;
3686
3687   /* Handle moving the header */
3688   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3689   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3690              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3691   gdk_window_move (tree_view->priv->drag_window, x, y);
3692   
3693   /* autoscroll, if needed */
3694   gtk_tree_view_horizontal_autoscroll (tree_view);
3695   /* Update the current reorder position and arrow; */
3696   gtk_tree_view_update_current_reorder (tree_view);
3697
3698   return TRUE;
3699 }
3700
3701 static void
3702 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3703 {
3704   remove_scroll_timeout (tree_view);
3705   gtk_grab_remove (GTK_WIDGET (tree_view));
3706
3707   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3708     {
3709       GtkTreePath *tmp_path;
3710
3711       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3712
3713       /* The anchor path should be set to the start path */
3714       tmp_path = _gtk_tree_view_find_path (tree_view,
3715                                            tree_view->priv->rubber_band_start_tree,
3716                                            tree_view->priv->rubber_band_start_node);
3717
3718       if (tree_view->priv->anchor)
3719         gtk_tree_row_reference_free (tree_view->priv->anchor);
3720
3721       tree_view->priv->anchor =
3722         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3723                                           tree_view->priv->model,
3724                                           tmp_path);
3725
3726       gtk_tree_path_free (tmp_path);
3727
3728       /* ... and the cursor to the end path */
3729       tmp_path = _gtk_tree_view_find_path (tree_view,
3730                                            tree_view->priv->rubber_band_end_tree,
3731                                            tree_view->priv->rubber_band_end_node);
3732       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3733       gtk_tree_path_free (tmp_path);
3734
3735       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3736     }
3737
3738   /* Clear status variables */
3739   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3740   tree_view->priv->rubber_band_shift = 0;
3741   tree_view->priv->rubber_band_ctrl = 0;
3742
3743   tree_view->priv->rubber_band_start_node = NULL;
3744   tree_view->priv->rubber_band_start_tree = NULL;
3745   tree_view->priv->rubber_band_end_node = NULL;
3746   tree_view->priv->rubber_band_end_tree = NULL;
3747 }
3748
3749 static void
3750 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3751                                                  GtkRBTree   *start_tree,
3752                                                  GtkRBNode   *start_node,
3753                                                  GtkRBTree   *end_tree,
3754                                                  GtkRBNode   *end_node,
3755                                                  gboolean     select,
3756                                                  gboolean     skip_start,
3757                                                  gboolean     skip_end)
3758 {
3759   if (start_node == end_node)
3760     return;
3761
3762   /* We skip the first node and jump inside the loop */
3763   if (skip_start)
3764     goto skip_first;
3765
3766   do
3767     {
3768       /* Small optimization by assuming insensitive nodes are never
3769        * selected.
3770        */
3771       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3772         {
3773           GtkTreePath *path;
3774           gboolean selectable;
3775
3776           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3777           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3778           gtk_tree_path_free (path);
3779
3780           if (!selectable)
3781             goto node_not_selectable;
3782         }
3783
3784       if (select)
3785         {
3786           if (tree_view->priv->rubber_band_shift)
3787             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3788           else if (tree_view->priv->rubber_band_ctrl)
3789             {
3790               /* Toggle the selection state */
3791               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3792                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3793               else
3794                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3795             }
3796           else
3797             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3798         }
3799       else
3800         {
3801           /* Mirror the above */
3802           if (tree_view->priv->rubber_band_shift)
3803             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3804           else if (tree_view->priv->rubber_band_ctrl)
3805             {
3806               /* Toggle the selection state */
3807               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3808                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3809               else
3810                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3811             }
3812           else
3813             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3814         }
3815
3816       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3817
3818 node_not_selectable:
3819       if (start_node == end_node)
3820         break;
3821
3822 skip_first:
3823
3824       if (start_node->children)
3825         {
3826           start_tree = start_node->children;
3827           start_node = start_tree->root;
3828           while (start_node->left != start_tree->nil)
3829             start_node = start_node->left;
3830         }
3831       else
3832         {
3833           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3834
3835           if (!start_tree)
3836             /* Ran out of tree */
3837             break;
3838         }
3839
3840       if (skip_end && start_node == end_node)
3841         break;
3842     }
3843   while (TRUE);
3844 }
3845
3846 static void
3847 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3848 {
3849   GtkRBTree *start_tree, *end_tree;
3850   GtkRBNode *start_node, *end_node;
3851
3852   _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);
3853   _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);
3854
3855   /* Handle the start area first */
3856   if (!tree_view->priv->rubber_band_start_node)
3857     {
3858       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3859                                                        start_tree,
3860                                                        start_node,
3861                                                        end_tree,
3862                                                        end_node,
3863                                                        TRUE,
3864                                                        FALSE,
3865                                                        FALSE);
3866     }
3867   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3868            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3869     {
3870       /* New node is above the old one; selection became bigger */
3871       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3872                                                        start_tree,
3873                                                        start_node,
3874                                                        tree_view->priv->rubber_band_start_tree,
3875                                                        tree_view->priv->rubber_band_start_node,
3876                                                        TRUE,
3877                                                        FALSE,
3878                                                        TRUE);
3879     }
3880   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3881            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3882     {
3883       /* New node is below the old one; selection became smaller */
3884       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3885                                                        tree_view->priv->rubber_band_start_tree,
3886                                                        tree_view->priv->rubber_band_start_node,
3887                                                        start_tree,
3888                                                        start_node,
3889                                                        FALSE,
3890                                                        FALSE,
3891                                                        TRUE);
3892     }
3893
3894   tree_view->priv->rubber_band_start_tree = start_tree;
3895   tree_view->priv->rubber_band_start_node = start_node;
3896
3897   /* Next, handle the end area */
3898   if (!tree_view->priv->rubber_band_end_node)
3899     {
3900       /* In the event this happens, start_node was also NULL; this case is
3901        * handled above.
3902        */
3903     }
3904   else if (!end_node)
3905     {
3906       /* Find the last node in the tree */
3907       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3908                                &end_tree, &end_node);
3909
3910       /* Selection reached end of the tree */
3911       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3912                                                        tree_view->priv->rubber_band_end_tree,
3913                                                        tree_view->priv->rubber_band_end_node,
3914                                                        end_tree,
3915                                                        end_node,
3916                                                        TRUE,
3917                                                        TRUE,
3918                                                        FALSE);
3919     }
3920   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3921            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3922     {
3923       /* New node is below the old one; selection became bigger */
3924       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3925                                                        tree_view->priv->rubber_band_end_tree,
3926                                                        tree_view->priv->rubber_band_end_node,
3927                                                        end_tree,
3928                                                        end_node,
3929                                                        TRUE,
3930                                                        TRUE,
3931                                                        FALSE);
3932     }
3933   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3934            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3935     {
3936       /* New node is above the old one; selection became smaller */
3937       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3938                                                        end_tree,
3939                                                        end_node,
3940                                                        tree_view->priv->rubber_band_end_tree,
3941                                                        tree_view->priv->rubber_band_end_node,
3942                                                        FALSE,
3943                                                        TRUE,
3944                                                        FALSE);
3945     }
3946
3947   tree_view->priv->rubber_band_end_tree = end_tree;
3948   tree_view->priv->rubber_band_end_node = end_node;
3949 }
3950
3951 static void
3952 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3953 {
3954   gint x, y;
3955   GdkRectangle old_area;
3956   GdkRectangle new_area;
3957   GdkRectangle common;
3958   GdkRegion *invalid_region;
3959
3960   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3961   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3962   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
3963   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
3964
3965   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
3966
3967   x = MAX (x, 0);
3968   y = MAX (y, 0) + tree_view->priv->dy;
3969
3970   new_area.x = MIN (tree_view->priv->press_start_x, x);
3971   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
3972   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
3973   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
3974
3975   invalid_region = gdk_region_rectangle (&old_area);
3976   gdk_region_union_with_rect (invalid_region, &new_area);
3977
3978   gdk_rectangle_intersect (&old_area, &new_area, &common);
3979   if (common.width > 2 && common.height > 2)
3980     {
3981       GdkRegion *common_region;
3982
3983       /* make sure the border is invalidated */
3984       common.x += 1;
3985       common.y += 1;
3986       common.width -= 2;
3987       common.height -= 2;
3988
3989       common_region = gdk_region_rectangle (&common);
3990
3991       gdk_region_subtract (invalid_region, common_region);
3992       gdk_region_destroy (common_region);
3993     }
3994
3995   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
3996
3997   gdk_region_destroy (invalid_region);
3998
3999   tree_view->priv->rubber_band_x = x;
4000   tree_view->priv->rubber_band_y = y;
4001
4002   gtk_tree_view_update_rubber_band_selection (tree_view);
4003 }
4004
4005 static void
4006 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4007                                 GdkRectangle *area)
4008 {
4009   cairo_t *cr;
4010   GdkRectangle rect;
4011   GdkRectangle rubber_rect;
4012
4013   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4014   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4015   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4016   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4017
4018   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4019     return;
4020
4021   cr = gdk_cairo_create (tree_view->priv->bin_window);
4022   cairo_set_line_width (cr, 1.0);
4023
4024   cairo_set_source_rgba (cr,
4025                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4026                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4027                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4028                          .25);
4029
4030   gdk_cairo_rectangle (cr, &rect);
4031   cairo_clip (cr);
4032   cairo_paint (cr);
4033
4034   cairo_set_source_rgb (cr,
4035                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4036                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4037                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4038
4039   cairo_rectangle (cr,
4040                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4041                    rubber_rect.width - 1, rubber_rect.height - 1);
4042   cairo_stroke (cr);
4043
4044   cairo_destroy (cr);
4045 }
4046
4047 static gboolean
4048 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4049                                  GdkEventMotion *event)
4050 {
4051   GtkTreeView *tree_view;
4052   GtkRBTree *tree;
4053   GtkRBNode *node;
4054   gint new_y;
4055
4056   tree_view = (GtkTreeView *) widget;
4057
4058   if (tree_view->priv->tree == NULL)
4059     return FALSE;
4060
4061   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4062     {
4063       gtk_grab_add (GTK_WIDGET (tree_view));
4064       gtk_tree_view_update_rubber_band (tree_view);
4065
4066       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4067     }
4068   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4069     {
4070       gtk_tree_view_update_rubber_band (tree_view);
4071
4072       add_scroll_timeout (tree_view);
4073     }
4074
4075   /* only check for an initiated drag when a button is pressed */
4076   if (tree_view->priv->pressed_button >= 0
4077       && !tree_view->priv->rubber_band_status)
4078     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4079
4080   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4081   if (new_y < 0)
4082     new_y = 0;
4083
4084   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4085
4086   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4087   if ((tree_view->priv->button_pressed_node != NULL) &&
4088       (tree_view->priv->button_pressed_node != node))
4089     node = NULL;
4090
4091   prelight_or_select (tree_view, tree, node, event->x, event->y);
4092
4093   return TRUE;
4094 }
4095
4096 static gboolean
4097 gtk_tree_view_motion (GtkWidget      *widget,
4098                       GdkEventMotion *event)
4099 {
4100   GtkTreeView *tree_view;
4101
4102   tree_view = (GtkTreeView *) widget;
4103
4104   /* Resizing a column */
4105   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4106     return gtk_tree_view_motion_resize_column (widget, event);
4107
4108   /* Drag column */
4109   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4110     return gtk_tree_view_motion_drag_column (widget, event);
4111
4112   /* Sanity check it */
4113   if (event->window == tree_view->priv->bin_window)
4114     return gtk_tree_view_motion_bin_window (widget, event);
4115
4116   return FALSE;
4117 }
4118
4119 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4120  * the tree is empty.
4121  */
4122 static void
4123 invalidate_empty_focus (GtkTreeView *tree_view)
4124 {
4125   GdkRectangle area;
4126
4127   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4128     return;
4129
4130   area.x = 0;
4131   area.y = 0;
4132   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4133   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4134 }
4135
4136 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4137  * is empty.
4138  */
4139 static void
4140 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4141 {
4142   gint w, h;
4143
4144   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4145     return;
4146
4147   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4148
4149   w -= 2;
4150   h -= 2;
4151
4152   if (w > 0 && h > 0)
4153     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4154                      tree_view->priv->bin_window,
4155                      GTK_WIDGET_STATE (tree_view),
4156                      clip_area,
4157                      GTK_WIDGET (tree_view),
4158                      NULL,
4159                      1, 1, w, h);
4160 }
4161
4162 static void
4163 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4164                                GdkEventExpose *event,
4165                                gint            n_visible_columns)
4166 {
4167   GList *list = tree_view->priv->columns;
4168   gint i = 0;
4169   gint current_x = 0;
4170
4171   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4172       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4173     return;
4174
4175   /* Only draw the lines for visible rows and columns */
4176   for (list = tree_view->priv->columns; list; list = list->next, i++)
4177     {
4178       GtkTreeViewColumn *column = list->data;
4179
4180       /* We don't want a line for the last column */
4181       if (i == n_visible_columns - 1)
4182         break;
4183
4184       if (! column->visible)
4185         continue;
4186
4187       current_x += column->width;
4188
4189       gdk_draw_line (event->window,
4190                      tree_view->priv->grid_line_gc,
4191                      current_x - 1, 0,
4192                      current_x - 1, tree_view->priv->height);
4193     }
4194 }
4195
4196 /* Warning: Very scary function.
4197  * Modify at your own risk
4198  *
4199  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4200  * FIXME: It's not...
4201  */
4202 static gboolean
4203 gtk_tree_view_bin_expose (GtkWidget      *widget,
4204                           GdkEventExpose *event)
4205 {
4206   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4207   GtkTreePath *path;
4208   GtkRBTree *tree;
4209   GList *list;
4210   GtkRBNode *node;
4211   GtkRBNode *cursor = NULL;
4212   GtkRBTree *cursor_tree = NULL;
4213   GtkRBNode *drag_highlight = NULL;
4214   GtkRBTree *drag_highlight_tree = NULL;
4215   GtkTreeIter iter;
4216   gint new_y;
4217   gint y_offset, cell_offset;
4218   gint max_height;
4219   gint depth;
4220   GdkRectangle background_area;
4221   GdkRectangle cell_area;
4222   guint flags;
4223   gint highlight_x;
4224   gint expander_cell_width;
4225   gint bin_window_width;
4226   gint bin_window_height;
4227   GtkTreePath *cursor_path;
4228   GtkTreePath *drag_dest_path;
4229   GList *first_column, *last_column;
4230   gint vertical_separator;
4231   gint horizontal_separator;
4232   gint focus_line_width;
4233   gboolean allow_rules;
4234   gboolean has_special_cell;
4235   gboolean rtl;
4236   gint n_visible_columns;
4237   gint pointer_x, pointer_y;
4238   gint grid_line_width;
4239   gboolean got_pointer = FALSE;
4240   gboolean row_ending_details;
4241   gboolean draw_vgrid_lines, draw_hgrid_lines;
4242
4243   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4244
4245   gtk_widget_style_get (widget,
4246                         "horizontal-separator", &horizontal_separator,
4247                         "vertical-separator", &vertical_separator,
4248                         "allow-rules", &allow_rules,
4249                         "focus-line-width", &focus_line_width,
4250                         "row-ending-details", &row_ending_details,
4251                         NULL);
4252
4253   if (tree_view->priv->tree == NULL)
4254     {
4255       draw_empty_focus (tree_view, &event->area);
4256       return TRUE;
4257     }
4258
4259   /* clip event->area to the visible area */
4260   if (event->area.height < 0)
4261     return TRUE;
4262
4263   validate_visible_area (tree_view);
4264
4265   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4266
4267   if (new_y < 0)
4268     new_y = 0;
4269   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4270   gdk_drawable_get_size (tree_view->priv->bin_window,
4271                          &bin_window_width, &bin_window_height);
4272
4273   if (tree_view->priv->height < bin_window_height)
4274     {
4275       gtk_paint_flat_box (widget->style,
4276                           event->window,
4277                           widget->state,
4278                           GTK_SHADOW_NONE,
4279                           &event->area,
4280                           widget,
4281                           "cell_even",
4282                           0, tree_view->priv->height,
4283                           bin_window_width,
4284                           bin_window_height - tree_view->priv->height);
4285     }
4286
4287   if (node == NULL)
4288     return TRUE;
4289
4290   /* find the path for the node */
4291   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4292                                    tree,
4293                                    node);
4294   gtk_tree_model_get_iter (tree_view->priv->model,
4295                            &iter,
4296                            path);
4297   depth = gtk_tree_path_get_depth (path);
4298   gtk_tree_path_free (path);
4299   
4300   cursor_path = NULL;
4301   drag_dest_path = NULL;
4302
4303   if (tree_view->priv->cursor)
4304     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4305
4306   if (cursor_path)
4307     _gtk_tree_view_find_node (tree_view, cursor_path,
4308                               &cursor_tree, &cursor);
4309
4310   if (tree_view->priv->drag_dest_row)
4311     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4312
4313   if (drag_dest_path)
4314     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4315                               &drag_highlight_tree, &drag_highlight);
4316
4317   draw_vgrid_lines =
4318     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4319     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4320   draw_hgrid_lines =
4321     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4322     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4323
4324   if (draw_vgrid_lines || draw_hgrid_lines)
4325     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4326   
4327   n_visible_columns = 0;
4328   for (list = tree_view->priv->columns; list; list = list->next)
4329     {
4330       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4331         continue;
4332       n_visible_columns ++;
4333     }
4334
4335   /* Find the last column */
4336   for (last_column = g_list_last (tree_view->priv->columns);
4337        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4338        last_column = last_column->prev)
4339     ;
4340
4341   /* and the first */
4342   for (first_column = g_list_first (tree_view->priv->columns);
4343        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4344        first_column = first_column->next)
4345     ;
4346
4347   /* Actually process the expose event.  To do this, we want to
4348    * start at the first node of the event, and walk the tree in
4349    * order, drawing each successive node.
4350    */
4351
4352   do
4353     {
4354       gboolean parity;
4355       gboolean is_separator = FALSE;
4356       gboolean is_first = FALSE;
4357       gboolean is_last = FALSE;
4358       
4359       is_separator = row_is_separator (tree_view, &iter, NULL);
4360
4361       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4362
4363       cell_offset = 0;
4364       highlight_x = 0; /* should match x coord of first cell */
4365       expander_cell_width = 0;
4366
4367       background_area.y = y_offset + event->area.y;
4368       background_area.height = max_height;
4369
4370       flags = 0;
4371
4372       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4373         flags |= GTK_CELL_RENDERER_PRELIT;
4374
4375       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4376         flags |= GTK_CELL_RENDERER_SELECTED;
4377
4378       parity = _gtk_rbtree_node_find_parity (tree, node);
4379
4380       /* we *need* to set cell data on all cells before the call
4381        * to _has_special_cell, else _has_special_cell() does not
4382        * return a correct value.
4383        */
4384       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4385            list;
4386            list = (rtl ? list->prev : list->next))
4387         {
4388           GtkTreeViewColumn *column = list->data;
4389           gtk_tree_view_column_cell_set_cell_data (column,
4390                                                    tree_view->priv->model,
4391                                                    &iter,
4392                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4393                                                    node->children?TRUE:FALSE);
4394         }
4395
4396       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4397
4398       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4399            list;
4400            list = (rtl ? list->prev : list->next))
4401         {
4402           GtkTreeViewColumn *column = list->data;
4403           const gchar *detail = NULL;
4404           GtkStateType state;
4405
4406           if (!column->visible)
4407             continue;
4408
4409           if (cell_offset > event->area.x + event->area.width ||
4410               cell_offset + column->width < event->area.x)
4411             {
4412               cell_offset += column->width;
4413               continue;
4414             }
4415
4416           if (column->show_sort_indicator)
4417             flags |= GTK_CELL_RENDERER_SORTED;
4418           else
4419             flags &= ~GTK_CELL_RENDERER_SORTED;
4420
4421           if (cursor == node)
4422             flags |= GTK_CELL_RENDERER_FOCUSED;
4423           else
4424             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4425
4426           background_area.x = cell_offset;
4427           background_area.width = column->width;
4428
4429           cell_area = background_area;
4430           cell_area.y += vertical_separator / 2;
4431           cell_area.x += horizontal_separator / 2;
4432           cell_area.height -= vertical_separator;
4433           cell_area.width -= horizontal_separator;
4434
4435           if (draw_vgrid_lines)
4436             {
4437               if (list == first_column)
4438                 {
4439                   cell_area.width -= grid_line_width / 2;
4440                 }
4441               else if (list == last_column)
4442                 {
4443                   cell_area.x += grid_line_width / 2;
4444                   cell_area.width -= grid_line_width / 2;
4445                 }
4446               else
4447                 {
4448                   cell_area.x += grid_line_width / 2;
4449                   cell_area.width -= grid_line_width;
4450                 }
4451             }
4452
4453           if (draw_hgrid_lines)
4454             {
4455               cell_area.y += grid_line_width / 2;
4456               cell_area.height -= grid_line_width;
4457             }
4458
4459           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4460             {
4461               cell_offset += column->width;
4462               continue;
4463             }
4464
4465           gtk_tree_view_column_cell_set_cell_data (column,
4466                                                    tree_view->priv->model,
4467                                                    &iter,
4468                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4469                                                    node->children?TRUE:FALSE);
4470
4471           /* Select the detail for drawing the cell.  relevant
4472            * factors are parity, sortedness, and whether to
4473            * display rules.
4474            */
4475           if (allow_rules && tree_view->priv->has_rules)
4476             {
4477               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4478                   n_visible_columns >= 3)
4479                 {
4480                   if (parity)
4481                     detail = "cell_odd_ruled_sorted";
4482                   else
4483                     detail = "cell_even_ruled_sorted";
4484                 }
4485               else
4486                 {
4487                   if (parity)
4488                     detail = "cell_odd_ruled";
4489                   else
4490                     detail = "cell_even_ruled";
4491                 }
4492             }
4493           else
4494             {
4495               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4496                   n_visible_columns >= 3)
4497                 {
4498                   if (parity)
4499                     detail = "cell_odd_sorted";
4500                   else
4501                     detail = "cell_even_sorted";
4502                 }
4503               else
4504                 {
4505                   if (parity)
4506                     detail = "cell_odd";
4507                   else
4508                     detail = "cell_even";
4509                 }
4510             }
4511
4512           g_assert (detail);
4513
4514           if (widget->state == GTK_STATE_INSENSITIVE)
4515             state = GTK_STATE_INSENSITIVE;          
4516           else if (flags & GTK_CELL_RENDERER_SELECTED)
4517             state = GTK_STATE_SELECTED;
4518           else
4519             state = GTK_STATE_NORMAL;
4520
4521           /* Draw background */
4522           if (row_ending_details)
4523             {
4524               char new_detail[128];
4525
4526               is_first = (rtl ? !list->next : !list->prev);
4527               is_last = (rtl ? !list->prev : !list->next);
4528
4529               /* (I don't like the snprintfs either, but couldn't find a
4530                * less messy way).
4531                */
4532               if (is_first && is_last)
4533                 g_snprintf (new_detail, 127, "%s", detail);
4534               else if (is_first)
4535                 g_snprintf (new_detail, 127, "%s_start", detail);
4536               else if (is_last)
4537                 g_snprintf (new_detail, 127, "%s_end", detail);
4538               else
4539                 g_snprintf (new_detail, 128, "%s_middle", detail);
4540
4541               gtk_paint_flat_box (widget->style,
4542                                   event->window,
4543                                   state,
4544                                   GTK_SHADOW_NONE,
4545                                   &event->area,
4546                                   widget,
4547                                   new_detail,
4548                                   background_area.x,
4549                                   background_area.y,
4550                                   background_area.width,
4551                                   background_area.height);
4552             }
4553           else
4554             {
4555               gtk_paint_flat_box (widget->style,
4556                                   event->window,
4557                                   state,
4558                                   GTK_SHADOW_NONE,
4559                                   &event->area,
4560                                   widget,
4561                                   detail,
4562                                   background_area.x,
4563                                   background_area.y,
4564                                   background_area.width,
4565                                   background_area.height);
4566             }
4567
4568           if (draw_hgrid_lines)
4569             {
4570               if (background_area.y > 0)
4571                 gdk_draw_line (event->window,
4572                                tree_view->priv->grid_line_gc,
4573                                background_area.x, background_area.y,
4574                                background_area.x + background_area.width,
4575                                background_area.y);
4576
4577               if (y_offset + max_height >= event->area.height)
4578                 gdk_draw_line (event->window,
4579                                tree_view->priv->grid_line_gc,
4580                                background_area.x, background_area.y + max_height,
4581                                background_area.x + background_area.width,
4582                                background_area.y + max_height);
4583             }
4584
4585           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4586               tree_view->priv->tree_lines_enabled)
4587             {
4588               gint x = background_area.x;
4589               gint mult = rtl ? -1 : 1;
4590               gint y0 = background_area.y;
4591               gint y1 = background_area.y + background_area.height/2;
4592               gint y2 = background_area.y + background_area.height;
4593
4594               if (rtl)
4595                 x += background_area.width - 1;
4596
4597               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4598                   && depth > 1)
4599                 {
4600                   gdk_draw_line (event->window,
4601                                  tree_view->priv->tree_line_gc,
4602                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4603                                  y1,
4604                                  x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4605                                  y1);
4606                 }
4607               else if (depth > 1)
4608                 {
4609                   gdk_draw_line (event->window,
4610                                  tree_view->priv->tree_line_gc,
4611                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4612                                  y1,
4613                                  x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4614                                  y1);
4615                 }
4616
4617               if (depth > 1)
4618                 {
4619                   gint i;
4620                   GtkRBNode *tmp_node;
4621                   GtkRBTree *tmp_tree;
4622
4623                   if (!_gtk_rbtree_next (tree, node))
4624                     gdk_draw_line (event->window,
4625                                    tree_view->priv->tree_line_gc,
4626                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4627                                    y0,
4628                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4629                                    y1);
4630                   else
4631                     gdk_draw_line (event->window,
4632                                    tree_view->priv->tree_line_gc,
4633                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4634                                    y0,
4635                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4636                                    y2);
4637
4638                   tmp_node = tree->parent_node;
4639                   tmp_tree = tree->parent_tree;
4640
4641                   for (i = depth - 2; i > 0; i--)
4642                     {
4643                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4644                         gdk_draw_line (event->window,
4645                                        tree_view->priv->tree_line_gc,
4646                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4647                                        y0,
4648                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4649                                        y2);
4650
4651                       tmp_node = tmp_tree->parent_node;
4652                       tmp_tree = tmp_tree->parent_tree;
4653                     }
4654                 }
4655             }
4656
4657           if (gtk_tree_view_is_expander_column (tree_view, column))
4658             {
4659               if (!rtl)
4660                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4661               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4662
4663               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4664                 {
4665                   if (!rtl)
4666                     cell_area.x += depth * tree_view->priv->expander_size;
4667                   cell_area.width -= depth * tree_view->priv->expander_size;
4668                 }
4669
4670               /* If we have an expander column, the highlight underline
4671                * starts with that column, so that it indicates which
4672                * level of the tree we're dropping at.
4673                */
4674               highlight_x = cell_area.x;
4675               expander_cell_width = cell_area.width;
4676
4677               if (is_separator)
4678                 gtk_paint_hline (widget->style,
4679                                  event->window,
4680                                  state,
4681                                  &cell_area,
4682                                  widget,
4683                                  NULL,
4684                                  cell_area.x,
4685                                  cell_area.x + cell_area.width,
4686                                  cell_area.y + cell_area.height / 2);
4687               else
4688                 _gtk_tree_view_column_cell_render (column,
4689                                                    event->window,
4690                                                    &background_area,
4691                                                    &cell_area,
4692                                                    &event->area,
4693                                                    flags);
4694               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4695                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4696                 {
4697                   if (!got_pointer)
4698                     {
4699                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4700                                               &pointer_x, &pointer_y, NULL);
4701                       got_pointer = TRUE;
4702                     }
4703
4704                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4705                                             tree,
4706                                             node,
4707                                             pointer_x, pointer_y);
4708                 }
4709             }
4710           else
4711             {
4712               if (is_separator)
4713                 gtk_paint_hline (widget->style,
4714                                  event->window,
4715                                  state,
4716                                  &cell_area,
4717                                  widget,
4718                                  NULL,
4719                                  cell_area.x,
4720                                  cell_area.x + cell_area.width,
4721                                  cell_area.y + cell_area.height / 2);
4722               else
4723                 _gtk_tree_view_column_cell_render (column,
4724                                                    event->window,
4725                                                    &background_area,
4726                                                    &cell_area,
4727                                                    &event->area,
4728                                                    flags);
4729             }
4730           if (node == cursor && has_special_cell &&
4731               ((column == tree_view->priv->focus_column &&
4732                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4733                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4734                (column == tree_view->priv->edited_column)))
4735             {
4736               _gtk_tree_view_column_cell_draw_focus (column,
4737                                                      event->window,
4738                                                      &background_area,
4739                                                      &cell_area,
4740                                                      &event->area,
4741                                                      flags);
4742             }
4743           cell_offset += column->width;
4744         }
4745
4746       if (node == drag_highlight)
4747         {
4748           /* Draw indicator for the drop
4749            */
4750           gint highlight_y = -1;
4751           GtkRBTree *tree = NULL;
4752           GtkRBNode *node = NULL;
4753           gint width;
4754
4755           switch (tree_view->priv->drag_dest_pos)
4756             {
4757             case GTK_TREE_VIEW_DROP_BEFORE:
4758               highlight_y = background_area.y - 1;
4759               if (highlight_y < 0)
4760                       highlight_y = 0;
4761               break;
4762
4763             case GTK_TREE_VIEW_DROP_AFTER:
4764               highlight_y = background_area.y + background_area.height - 1;
4765               break;
4766
4767             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4768             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4769               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4770
4771               if (tree == NULL)
4772                 break;
4773               gdk_drawable_get_size (tree_view->priv->bin_window,
4774                                      &width, NULL);
4775
4776               if (row_ending_details)
4777                 gtk_paint_focus (widget->style,
4778                                  tree_view->priv->bin_window,
4779                                  GTK_WIDGET_STATE (widget),
4780                                  &event->area,
4781                                  widget,
4782                                  (is_first
4783                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4784                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4785                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4786                                  - focus_line_width / 2,
4787                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4788                                - focus_line_width + 1);
4789               else
4790                 gtk_paint_focus (widget->style,
4791                                  tree_view->priv->bin_window,
4792                                  GTK_WIDGET_STATE (widget),
4793                                  &event->area,
4794                                  widget,
4795                                  "treeview-drop-indicator",
4796                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4797                                  - focus_line_width / 2,
4798                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4799                                  - focus_line_width + 1);
4800               break;
4801             }
4802
4803           if (highlight_y >= 0)
4804             {
4805               gdk_draw_line (event->window,
4806                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4807                              rtl ? highlight_x + expander_cell_width : highlight_x,
4808                              highlight_y,
4809                              rtl ? 0 : bin_window_width,
4810                              highlight_y);
4811             }
4812         }
4813
4814       /* draw the big row-spanning focus rectangle, if needed */
4815       if (!has_special_cell && node == cursor &&
4816           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4817           GTK_WIDGET_HAS_FOCUS (widget))
4818         {
4819           gint tmp_y, tmp_height;
4820           gint width;
4821           GtkStateType focus_rect_state;
4822
4823           focus_rect_state =
4824             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4825             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4826              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4827               GTK_STATE_NORMAL));
4828
4829           gdk_drawable_get_size (tree_view->priv->bin_window,
4830                                  &width, NULL);
4831           
4832           if (draw_hgrid_lines)
4833             {
4834               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4835               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4836             }
4837           else
4838             {
4839               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4840               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4841             }
4842
4843           if (row_ending_details)
4844             gtk_paint_focus (widget->style,
4845                              tree_view->priv->bin_window,
4846                              focus_rect_state,
4847                              &event->area,
4848                              widget,
4849                              (is_first
4850                               ? (is_last ? "treeview" : "treeview-left" )
4851                               : (is_last ? "treeview-right" : "treeview-middle" )),
4852                              0, tmp_y,
4853                              width, tmp_height);
4854           else
4855             gtk_paint_focus (widget->style,
4856                              tree_view->priv->bin_window,
4857                              focus_rect_state,
4858                              &event->area,
4859                              widget,
4860                              "treeview",
4861                              0, tmp_y,
4862                              width, tmp_height);
4863         }
4864
4865       y_offset += max_height;
4866       if (node->children)
4867         {
4868           GtkTreeIter parent = iter;
4869           gboolean has_child;
4870
4871           tree = node->children;
4872           node = tree->root;
4873
4874           g_assert (node != tree->nil);
4875
4876           while (node->left != tree->nil)
4877             node = node->left;
4878           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4879                                                     &iter,
4880                                                     &parent);
4881           depth++;
4882
4883           /* Sanity Check! */
4884           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4885         }
4886       else
4887         {
4888           gboolean done = FALSE;
4889
4890           do
4891             {
4892               node = _gtk_rbtree_next (tree, node);
4893               if (node != NULL)
4894                 {
4895                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4896                   done = TRUE;
4897
4898                   /* Sanity Check! */
4899                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4900                 }
4901               else
4902                 {
4903                   GtkTreeIter parent_iter = iter;
4904                   gboolean has_parent;
4905
4906                   node = tree->parent_node;
4907                   tree = tree->parent_tree;
4908                   if (tree == NULL)
4909                     /* we should go to done to free some memory */
4910                     goto done;
4911                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4912                                                            &iter,
4913                                                            &parent_iter);
4914                   depth--;
4915
4916                   /* Sanity check */
4917                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4918                 }
4919             }
4920           while (!done);
4921         }
4922     }
4923   while (y_offset < event->area.height);
4924
4925 done:
4926   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
4927
4928  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4929    {
4930      GdkRectangle *rectangles;
4931      gint n_rectangles;
4932
4933      gdk_region_get_rectangles (event->region,
4934                                 &rectangles,
4935                                 &n_rectangles);
4936
4937      while (n_rectangles--)
4938        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
4939
4940      g_free (rectangles);
4941    }
4942
4943   if (cursor_path)
4944     gtk_tree_path_free (cursor_path);
4945
4946   if (drag_dest_path)
4947     gtk_tree_path_free (drag_dest_path);
4948
4949   return FALSE;
4950 }
4951
4952 static gboolean
4953 gtk_tree_view_expose (GtkWidget      *widget,
4954                       GdkEventExpose *event)
4955 {
4956   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4957
4958   if (event->window == tree_view->priv->bin_window)
4959     {
4960       gboolean retval;
4961       GList *tmp_list;
4962
4963       retval = gtk_tree_view_bin_expose (widget, event);
4964
4965       /* We can't just chain up to Container::expose as it will try to send the
4966        * event to the headers, so we handle propagating it to our children
4967        * (eg. widgets being edited) ourselves.
4968        */
4969       tmp_list = tree_view->priv->children;
4970       while (tmp_list)
4971         {
4972           GtkTreeViewChild *child = tmp_list->data;
4973           tmp_list = tmp_list->next;
4974
4975           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
4976         }
4977
4978       return retval;
4979     }
4980
4981   else if (event->window == tree_view->priv->header_window)
4982     {
4983       GList *list;
4984       
4985       for (list = tree_view->priv->columns; list != NULL; list = list->next)
4986         {
4987           GtkTreeViewColumn *column = list->data;
4988
4989           if (column == tree_view->priv->drag_column)
4990             continue;
4991
4992           if (column->visible)
4993             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4994                                             column->button,
4995                                             event);
4996         }
4997     }
4998   else if (event->window == tree_view->priv->drag_window)
4999     {
5000       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5001                                       tree_view->priv->drag_column->button,
5002                                       event);
5003     }
5004   return TRUE;
5005 }
5006
5007 enum
5008 {
5009   DROP_HOME,
5010   DROP_RIGHT,
5011   DROP_LEFT,
5012   DROP_END
5013 };
5014
5015 /* returns 0x1 when no column has been found -- yes it's hackish */
5016 static GtkTreeViewColumn *
5017 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5018                                GtkTreeViewColumn *column,
5019                                gint               drop_position)
5020 {
5021   GtkTreeViewColumn *left_column = NULL;
5022   GtkTreeViewColumn *cur_column = NULL;
5023   GList *tmp_list;
5024
5025   if (!column->reorderable)
5026     return (GtkTreeViewColumn *)0x1;
5027
5028   switch (drop_position)
5029     {
5030       case DROP_HOME:
5031         /* find first column where we can drop */
5032         tmp_list = tree_view->priv->columns;
5033         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5034           return (GtkTreeViewColumn *)0x1;
5035
5036         while (tmp_list)
5037           {
5038             g_assert (tmp_list);
5039
5040             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5041             tmp_list = tmp_list->next;
5042
5043             if (left_column && left_column->visible == FALSE)
5044               continue;
5045
5046             if (!tree_view->priv->column_drop_func)
5047               return left_column;
5048
5049             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5050               {
5051                 left_column = cur_column;
5052                 continue;
5053               }
5054
5055             return left_column;
5056           }
5057
5058         if (!tree_view->priv->column_drop_func)
5059           return left_column;
5060
5061         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5062           return left_column;
5063         else
5064           return (GtkTreeViewColumn *)0x1;
5065         break;
5066
5067       case DROP_RIGHT:
5068         /* find first column after column where we can drop */
5069         tmp_list = tree_view->priv->columns;
5070
5071         for (; tmp_list; tmp_list = tmp_list->next)
5072           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5073             break;
5074
5075         if (!tmp_list || !tmp_list->next)
5076           return (GtkTreeViewColumn *)0x1;
5077
5078         tmp_list = tmp_list->next;
5079         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5080         tmp_list = tmp_list->next;
5081
5082         while (tmp_list)
5083           {
5084             g_assert (tmp_list);
5085
5086             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5087             tmp_list = tmp_list->next;
5088
5089             if (left_column && left_column->visible == FALSE)
5090               {
5091                 left_column = cur_column;
5092                 if (tmp_list)
5093                   tmp_list = tmp_list->next;
5094                 continue;
5095               }
5096
5097             if (!tree_view->priv->column_drop_func)
5098               return left_column;
5099
5100             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5101               {
5102                 left_column = cur_column;
5103                 continue;
5104               }
5105
5106             return left_column;
5107           }
5108
5109         if (!tree_view->priv->column_drop_func)
5110           return left_column;
5111
5112         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5113           return left_column;
5114         else
5115           return (GtkTreeViewColumn *)0x1;
5116         break;
5117
5118       case DROP_LEFT:
5119         /* find first column before column where we can drop */
5120         tmp_list = tree_view->priv->columns;
5121
5122         for (; tmp_list; tmp_list = tmp_list->next)
5123           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5124             break;
5125
5126         if (!tmp_list || !tmp_list->prev)
5127           return (GtkTreeViewColumn *)0x1;
5128
5129         tmp_list = tmp_list->prev;
5130         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5131         tmp_list = tmp_list->prev;
5132
5133         while (tmp_list)
5134           {
5135             g_assert (tmp_list);
5136
5137             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5138
5139             if (left_column && !left_column->visible)
5140               {
5141                 /*if (!tmp_list->prev)
5142                   return (GtkTreeViewColumn *)0x1;
5143                   */
5144 /*
5145                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5146                 tmp_list = tmp_list->prev->prev;
5147                 continue;*/
5148
5149                 cur_column = left_column;
5150                 if (tmp_list)
5151                   tmp_list = tmp_list->prev;
5152                 continue;
5153               }
5154
5155             if (!tree_view->priv->column_drop_func)
5156               return left_column;
5157
5158             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5159               return left_column;
5160
5161             cur_column = left_column;
5162             tmp_list = tmp_list->prev;
5163           }
5164
5165         if (!tree_view->priv->column_drop_func)
5166           return NULL;
5167
5168         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5169           return NULL;
5170         else
5171           return (GtkTreeViewColumn *)0x1;
5172         break;
5173
5174       case DROP_END:
5175         /* same as DROP_HOME case, but doing it backwards */
5176         tmp_list = g_list_last (tree_view->priv->columns);
5177         cur_column = NULL;
5178
5179         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5180           return (GtkTreeViewColumn *)0x1;
5181
5182         while (tmp_list)
5183           {
5184             g_assert (tmp_list);
5185
5186             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5187
5188             if (left_column && !left_column->visible)
5189               {
5190                 cur_column = left_column;
5191                 tmp_list = tmp_list->prev;
5192               }
5193
5194             if (!tree_view->priv->column_drop_func)
5195               return left_column;
5196
5197             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5198               return left_column;
5199
5200             cur_column = left_column;
5201             tmp_list = tmp_list->prev;
5202           }
5203
5204         if (!tree_view->priv->column_drop_func)
5205           return NULL;
5206
5207         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5208           return NULL;
5209         else
5210           return (GtkTreeViewColumn *)0x1;
5211         break;
5212     }
5213
5214   return (GtkTreeViewColumn *)0x1;
5215 }
5216
5217 static gboolean
5218 gtk_tree_view_key_press (GtkWidget   *widget,
5219                          GdkEventKey *event)
5220 {
5221   GtkTreeView *tree_view = (GtkTreeView *) widget;
5222
5223   if (tree_view->priv->rubber_band_status)
5224     {
5225       if (event->keyval == GDK_Escape)
5226         gtk_tree_view_stop_rubber_band (tree_view);
5227
5228       return TRUE;
5229     }
5230
5231   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5232     {
5233       if (event->keyval == GDK_Escape)
5234         {
5235           tree_view->priv->cur_reorder = NULL;
5236           gtk_tree_view_button_release_drag_column (widget, NULL);
5237         }
5238       return TRUE;
5239     }
5240
5241   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5242     {
5243       GList *focus_column;
5244       gboolean rtl;
5245
5246       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5247
5248       for (focus_column = tree_view->priv->columns;
5249            focus_column;
5250            focus_column = focus_column->next)
5251         {
5252           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5253
5254           if (GTK_WIDGET_HAS_FOCUS (column->button))
5255             break;
5256         }
5257
5258       if (focus_column &&
5259           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5260           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5261            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5262         {
5263           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5264
5265           if (!column->resizable)
5266             {
5267               gtk_widget_error_bell (widget);
5268               return TRUE;
5269             }
5270
5271           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5272               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5273             {
5274               gint old_width = column->resized_width;
5275
5276               column->resized_width = MAX (column->resized_width,
5277                                            column->width);
5278               column->resized_width -= 2;
5279               if (column->resized_width < 0)
5280                 column->resized_width = 0;
5281
5282               if (column->min_width == -1)
5283                 column->resized_width = MAX (column->button->requisition.width,
5284                                              column->resized_width);
5285               else
5286                 column->resized_width = MAX (column->min_width,
5287                                              column->resized_width);
5288
5289               if (column->max_width != -1)
5290                 column->resized_width = MIN (column->resized_width,
5291                                              column->max_width);
5292
5293               column->use_resized_width = TRUE;
5294
5295               if (column->resized_width != old_width)
5296                 gtk_widget_queue_resize (widget);
5297               else
5298                 gtk_widget_error_bell (widget);
5299             }
5300           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5301                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5302             {
5303               gint old_width = column->resized_width;
5304
5305               column->resized_width = MAX (column->resized_width,
5306                                            column->width);
5307               column->resized_width += 2;
5308
5309               if (column->max_width != -1)
5310                 column->resized_width = MIN (column->resized_width,
5311                                              column->max_width);
5312
5313               column->use_resized_width = TRUE;
5314
5315               if (column->resized_width != old_width)
5316                 gtk_widget_queue_resize (widget);
5317               else
5318                 gtk_widget_error_bell (widget);
5319             }
5320
5321           return TRUE;
5322         }
5323
5324       if (focus_column &&
5325           (event->state & GDK_MOD1_MASK) &&
5326           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5327            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5328            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5329            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5330         {
5331           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5332
5333           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5334               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5335             {
5336               GtkTreeViewColumn *col;
5337               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5338               if (col != (GtkTreeViewColumn *)0x1)
5339                 gtk_tree_view_move_column_after (tree_view, column, col);
5340               else
5341                 gtk_widget_error_bell (widget);
5342             }
5343           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5344                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5345             {
5346               GtkTreeViewColumn *col;
5347               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5348               if (col != (GtkTreeViewColumn *)0x1)
5349                 gtk_tree_view_move_column_after (tree_view, column, col);
5350               else
5351                 gtk_widget_error_bell (widget);
5352             }
5353           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5354             {
5355               GtkTreeViewColumn *col;
5356               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5357               if (col != (GtkTreeViewColumn *)0x1)
5358                 gtk_tree_view_move_column_after (tree_view, column, col);
5359               else
5360                 gtk_widget_error_bell (widget);
5361             }
5362           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5363             {
5364               GtkTreeViewColumn *col;
5365               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5366               if (col != (GtkTreeViewColumn *)0x1)
5367                 gtk_tree_view_move_column_after (tree_view, column, col);
5368               else
5369                 gtk_widget_error_bell (widget);
5370             }
5371
5372           return TRUE;
5373         }
5374     }
5375
5376   /* Chain up to the parent class.  It handles the keybindings. */
5377   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5378     return TRUE;
5379
5380   /* We pass the event to the search_entry.  If its text changes, then we start
5381    * the typeahead find capabilities. */
5382   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5383       && tree_view->priv->enable_search
5384       && !tree_view->priv->search_custom_entry_set)
5385     {
5386       GdkEvent *new_event;
5387       char *old_text;
5388       const char *new_text;
5389       gboolean retval;
5390       GdkScreen *screen;
5391       gboolean text_modified;
5392       gulong popup_menu_id;
5393
5394       gtk_tree_view_ensure_interactive_directory (tree_view);
5395
5396       /* Make a copy of the current text */
5397       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5398       new_event = gdk_event_copy ((GdkEvent *) event);
5399       g_object_unref (((GdkEventKey *) new_event)->window);
5400       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5401       gtk_widget_realize (tree_view->priv->search_window);
5402
5403       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5404                                         "popup-menu", G_CALLBACK (gtk_true),
5405                                         NULL);
5406
5407       /* Move the entry off screen */
5408       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5409       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5410                        gdk_screen_get_width (screen) + 1,
5411                        gdk_screen_get_height (screen) + 1);
5412       gtk_widget_show (tree_view->priv->search_window);
5413
5414       /* Send the event to the window.  If the preedit_changed signal is emitted
5415        * during this event, we will set priv->imcontext_changed  */
5416       tree_view->priv->imcontext_changed = FALSE;
5417       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5418       gdk_event_free (new_event);
5419       gtk_widget_hide (tree_view->priv->search_window);
5420
5421       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5422                                    popup_menu_id);
5423
5424       /* We check to make sure that the entry tried to handle the text, and that
5425        * the text has changed.
5426        */
5427       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5428       text_modified = strcmp (old_text, new_text) != 0;
5429       g_free (old_text);
5430       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5431           (retval && text_modified))               /* ...or the text was modified */
5432         {
5433           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5434             {
5435               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5436               return TRUE;
5437             }
5438           else
5439             {
5440               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5441               return FALSE;
5442             }
5443         }
5444     }
5445
5446   return FALSE;
5447 }
5448
5449 static gboolean
5450 gtk_tree_view_key_release (GtkWidget   *widget,
5451                            GdkEventKey *event)
5452 {
5453   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5454
5455   if (tree_view->priv->rubber_band_status)
5456     return TRUE;
5457
5458   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5459 }
5460
5461 /* FIXME Is this function necessary? Can I get an enter_notify event
5462  * w/o either an expose event or a mouse motion event?
5463  */
5464 static gboolean
5465 gtk_tree_view_enter_notify (GtkWidget        *widget,
5466                             GdkEventCrossing *event)
5467 {
5468   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5469   GtkRBTree *tree;
5470   GtkRBNode *node;
5471   gint new_y;
5472
5473   /* Sanity check it */
5474   if (event->window != tree_view->priv->bin_window)
5475     return FALSE;
5476
5477   if (tree_view->priv->tree == NULL)
5478     return FALSE;
5479
5480   /* find the node internally */
5481   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5482   if (new_y < 0)
5483     new_y = 0;
5484   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5485
5486   if ((tree_view->priv->button_pressed_node == NULL) ||
5487       (tree_view->priv->button_pressed_node == node))
5488     prelight_or_select (tree_view, tree, node, event->x, event->y);
5489
5490   return TRUE;
5491 }
5492
5493 static gboolean
5494 gtk_tree_view_leave_notify (GtkWidget        *widget,
5495                             GdkEventCrossing *event)
5496 {
5497   GtkTreeView *tree_view;
5498
5499   if (event->mode == GDK_CROSSING_GRAB)
5500     return TRUE;
5501
5502   tree_view = GTK_TREE_VIEW (widget);
5503
5504   if (tree_view->priv->prelight_node)
5505     _gtk_tree_view_queue_draw_node (tree_view,
5506                                    tree_view->priv->prelight_tree,
5507                                    tree_view->priv->prelight_node,
5508                                    NULL);
5509
5510   prelight_or_select (tree_view,
5511                       NULL, NULL,
5512                       -1000, -1000); /* coords not possibly over an arrow */
5513
5514   return TRUE;
5515 }
5516
5517
5518 static gint
5519 gtk_tree_view_focus_out (GtkWidget     *widget,
5520                          GdkEventFocus *event)
5521 {
5522   GtkTreeView *tree_view;
5523
5524   tree_view = GTK_TREE_VIEW (widget);
5525
5526   gtk_widget_queue_draw (widget);
5527
5528   /* destroy interactive search dialog */
5529   if (tree_view->priv->search_window)
5530     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5531
5532   return FALSE;
5533 }
5534
5535
5536 /* Incremental Reflow
5537  */
5538
5539 static void
5540 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5541                                  GtkRBTree   *tree,
5542                                  GtkRBNode   *node)
5543 {
5544   gint y;
5545
5546   y = _gtk_rbtree_node_find_offset (tree, node)
5547     - tree_view->priv->vadjustment->value
5548     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5549
5550   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5551                               0, y,
5552                               GTK_WIDGET (tree_view)->allocation.width,
5553                               GTK_RBNODE_GET_HEIGHT (node));
5554 }
5555
5556 static gboolean
5557 node_is_visible (GtkTreeView *tree_view,
5558                  GtkRBTree   *tree,
5559                  GtkRBNode   *node)
5560 {
5561   int y;
5562   int height;
5563
5564   y = _gtk_rbtree_node_find_offset (tree, node);
5565   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5566
5567   if (y >= tree_view->priv->vadjustment->value &&
5568       y + height <= (tree_view->priv->vadjustment->value
5569                      + tree_view->priv->vadjustment->page_size))
5570     return TRUE;
5571
5572   return FALSE;
5573 }
5574
5575 /* Returns TRUE if it updated the size
5576  */
5577 static gboolean
5578 validate_row (GtkTreeView *tree_view,
5579               GtkRBTree   *tree,
5580               GtkRBNode   *node,
5581               GtkTreeIter *iter,
5582               GtkTreePath *path)
5583 {
5584   GtkTreeViewColumn *column;
5585   GList *list, *first_column, *last_column;
5586   gint height = 0;
5587   gint horizontal_separator;
5588   gint vertical_separator;
5589   gint focus_line_width;
5590   gint depth = gtk_tree_path_get_depth (path);
5591   gboolean retval = FALSE;
5592   gboolean is_separator = FALSE;
5593   gboolean draw_vgrid_lines, draw_hgrid_lines;
5594   gint focus_pad;
5595   gint grid_line_width;
5596   gboolean wide_separators;
5597   gint separator_height;
5598
5599   /* double check the row needs validating */
5600   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5601       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5602     return FALSE;
5603
5604   is_separator = row_is_separator (tree_view, iter, NULL);
5605
5606   gtk_widget_style_get (GTK_WIDGET (tree_view),
5607                         "focus-padding", &focus_pad,
5608                         "focus-line-width", &focus_line_width,
5609                         "horizontal-separator", &horizontal_separator,
5610                         "vertical-separator", &vertical_separator,
5611                         "grid-line-width", &grid_line_width,
5612                         "wide-separators",  &wide_separators,
5613                         "separator-height", &separator_height,
5614                         NULL);
5615   
5616   draw_vgrid_lines =
5617     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5618     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5619   draw_hgrid_lines =
5620     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5621     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5622
5623   for (last_column = g_list_last (tree_view->priv->columns);
5624        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5625        last_column = last_column->prev)
5626     ;
5627
5628   for (first_column = g_list_first (tree_view->priv->columns);
5629        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5630        first_column = first_column->next)
5631     ;
5632
5633   for (list = tree_view->priv->columns; list; list = list->next)
5634     {
5635       gint tmp_width;
5636       gint tmp_height;
5637
5638       column = list->data;
5639
5640       if (! column->visible)
5641         continue;
5642
5643       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5644         continue;
5645
5646       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5647                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5648                                                node->children?TRUE:FALSE);
5649       gtk_tree_view_column_cell_get_size (column,
5650                                           NULL, NULL, NULL,
5651                                           &tmp_width, &tmp_height);
5652
5653       if (!is_separator)
5654         {
5655           tmp_height += vertical_separator;
5656           height = MAX (height, tmp_height);
5657           height = MAX (height, tree_view->priv->expander_size);
5658         }
5659       else
5660         {
5661           if (wide_separators)
5662             height = separator_height + 2 * focus_pad;
5663           else
5664             height = 2 + 2 * focus_pad;
5665         }
5666
5667       if (gtk_tree_view_is_expander_column (tree_view, column))
5668         {
5669           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5670
5671           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5672             tmp_width += depth * tree_view->priv->expander_size;
5673         }
5674       else
5675         tmp_width = tmp_width + horizontal_separator;
5676
5677       if (draw_vgrid_lines)
5678         {
5679           if (list->data == first_column || list->data == last_column)
5680             tmp_width += grid_line_width / 2.0;
5681           else
5682             tmp_width += grid_line_width;
5683         }
5684
5685       if (tmp_width > column->requested_width)
5686         {
5687           retval = TRUE;
5688           column->requested_width = tmp_width;
5689         }
5690     }
5691
5692   if (draw_hgrid_lines)
5693     height += grid_line_width;
5694
5695   if (height != GTK_RBNODE_GET_HEIGHT (node))
5696     {
5697       retval = TRUE;
5698       _gtk_rbtree_node_set_height (tree, node, height);
5699     }
5700   _gtk_rbtree_node_mark_valid (tree, node);
5701   tree_view->priv->post_validation_flag = TRUE;
5702
5703   return retval;
5704 }
5705
5706
5707 static void
5708 validate_visible_area (GtkTreeView *tree_view)
5709 {
5710   GtkTreePath *path = NULL;
5711   GtkTreePath *above_path = NULL;
5712   GtkTreeIter iter;
5713   GtkRBTree *tree = NULL;
5714   GtkRBNode *node = NULL;
5715   gboolean need_redraw = FALSE;
5716   gboolean size_changed = FALSE;
5717   gint total_height;
5718   gint area_above = 0;
5719   gint area_below = 0;
5720
5721   if (tree_view->priv->tree == NULL)
5722     return;
5723
5724   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5725       tree_view->priv->scroll_to_path == NULL)
5726     return;
5727
5728   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5729
5730   if (total_height == 0)
5731     return;
5732
5733   /* First, we check to see if we need to scroll anywhere
5734    */
5735   if (tree_view->priv->scroll_to_path)
5736     {
5737       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5738       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5739         {
5740           /* we are going to scroll, and will update dy */
5741           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5742           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5743               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5744             {
5745               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5746               if (validate_row (tree_view, tree, node, &iter, path))
5747                 size_changed = TRUE;
5748             }
5749
5750           if (tree_view->priv->scroll_to_use_align)
5751             {
5752               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5753               area_above = (total_height - height) *
5754                 tree_view->priv->scroll_to_row_align;
5755               area_below = total_height - area_above - height;
5756               area_above = MAX (area_above, 0);
5757               area_below = MAX (area_below, 0);
5758             }
5759           else
5760             {
5761               /* two cases:
5762                * 1) row not visible
5763                * 2) row visible
5764                */
5765               gint dy;
5766               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5767
5768               dy = _gtk_rbtree_node_find_offset (tree, node);
5769
5770               if (dy >= tree_view->priv->vadjustment->value &&
5771                   dy + height <= (tree_view->priv->vadjustment->value
5772                                   + tree_view->priv->vadjustment->page_size))
5773                 {
5774                   /* row visible: keep the row at the same position */
5775                   area_above = dy - tree_view->priv->vadjustment->value;
5776                   area_below = (tree_view->priv->vadjustment->value +
5777                                 tree_view->priv->vadjustment->page_size)
5778                                - dy - height;
5779                 }
5780               else
5781                 {
5782                   /* row not visible */
5783                   if (dy >= 0
5784                       && dy + height <= tree_view->priv->vadjustment->page_size)
5785                     {
5786                       /* row at the beginning -- fixed */
5787                       area_above = dy;
5788                       area_below = tree_view->priv->vadjustment->page_size
5789                                    - area_above - height;
5790                     }
5791                   else if (dy >= (tree_view->priv->vadjustment->upper -
5792                                   tree_view->priv->vadjustment->page_size))
5793                     {
5794                       /* row at the end -- fixed */
5795                       area_above = dy - (tree_view->priv->vadjustment->upper -
5796                                    tree_view->priv->vadjustment->page_size);
5797                       area_below = tree_view->priv->vadjustment->page_size -
5798                                    area_above - height;
5799
5800                       if (area_below < 0)
5801                         {
5802                           area_above = tree_view->priv->vadjustment->page_size - height;
5803                           area_below = 0;
5804                         }
5805                     }
5806                   else
5807                     {
5808                       /* row somewhere in the middle, bring it to the top
5809                        * of the view
5810                        */
5811                       area_above = 0;
5812                       area_below = total_height - height;
5813                     }
5814                 }
5815             }
5816         }
5817       else
5818         /* the scroll to isn't valid; ignore it.
5819          */
5820         {
5821           if (tree_view->priv->scroll_to_path && !path)
5822             {
5823               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5824               tree_view->priv->scroll_to_path = NULL;
5825             }
5826           if (path)
5827             gtk_tree_path_free (path);
5828           path = NULL;
5829         }      
5830     }
5831
5832   /* We didn't have a scroll_to set, so we just handle things normally
5833    */
5834   if (path == NULL)
5835     {
5836       gint offset;
5837
5838       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5839                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5840                                         &tree, &node);
5841       if (node == NULL)
5842         {
5843           /* In this case, nothing has been validated */
5844           path = gtk_tree_path_new_first ();
5845           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5846         }
5847       else
5848         {
5849           path = _gtk_tree_view_find_path (tree_view, tree, node);
5850           total_height += offset;
5851         }
5852
5853       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5854
5855       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5856           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5857         {
5858           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5859           if (validate_row (tree_view, tree, node, &iter, path))
5860             size_changed = TRUE;
5861         }
5862       area_above = 0;
5863       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5864     }
5865
5866   above_path = gtk_tree_path_copy (path);
5867
5868   /* if we do not validate any row above the new top_row, we will make sure
5869    * that the row immediately above top_row has been validated. (if we do not
5870    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5871    * when invalidated that row's height will be zero. and this will mess up
5872    * scrolling).
5873    */
5874   if (area_above == 0)
5875     {
5876       GtkRBTree *tmptree;
5877       GtkRBNode *tmpnode;
5878
5879       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5880       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5881
5882       if (tmpnode)
5883         {
5884           GtkTreePath *tmppath;
5885           GtkTreeIter tmpiter;
5886
5887           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5888           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5889
5890           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5891               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5892             {
5893               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5894               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5895                 size_changed = TRUE;
5896             }
5897
5898           gtk_tree_path_free (tmppath);
5899         }
5900     }
5901
5902   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5903    * backwards is much slower then forward, as there is no iter_prev function.
5904    * We go forwards first in case we run out of tree.  Then we go backwards to
5905    * fill out the top.
5906    */
5907   while (node && area_below > 0)
5908     {
5909       if (node->children)
5910         {
5911           GtkTreeIter parent = iter;
5912           gboolean has_child;
5913
5914           tree = node->children;
5915           node = tree->root;
5916
5917           g_assert (node != tree->nil);
5918
5919           while (node->left != tree->nil)
5920             node = node->left;
5921           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5922                                                     &iter,
5923                                                     &parent);
5924           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
5925           gtk_tree_path_down (path);
5926         }
5927       else
5928         {
5929           gboolean done = FALSE;
5930           do
5931             {
5932               node = _gtk_rbtree_next (tree, node);
5933               if (node != NULL)
5934                 {
5935                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5936                   done = TRUE;
5937                   gtk_tree_path_next (path);
5938
5939                   /* Sanity Check! */
5940                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
5941                 }
5942               else
5943                 {
5944                   GtkTreeIter parent_iter = iter;
5945                   gboolean has_parent;
5946
5947                   node = tree->parent_node;
5948                   tree = tree->parent_tree;
5949                   if (tree == NULL)
5950                     break;
5951                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5952                                                            &iter,
5953                                                            &parent_iter);
5954                   gtk_tree_path_up (path);
5955
5956                   /* Sanity check */
5957                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
5958                 }
5959             }
5960           while (!done);
5961         }
5962
5963       if (!node)
5964         break;
5965
5966       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5967           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5968         {
5969           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5970           if (validate_row (tree_view, tree, node, &iter, path))
5971               size_changed = TRUE;
5972         }
5973
5974       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5975     }
5976   gtk_tree_path_free (path);
5977
5978   /* If we ran out of tree, and have extra area_below left, we need to add it
5979    * to area_above */
5980   if (area_below > 0)
5981     area_above += area_below;
5982
5983   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
5984
5985   /* We walk backwards */
5986   while (area_above > 0)
5987     {
5988       _gtk_rbtree_prev_full (tree, node, &tree, &node);
5989       if (! gtk_tree_path_prev (above_path) && node != NULL)
5990         {
5991           gtk_tree_path_free (above_path);
5992           above_path = _gtk_tree_view_find_path (tree_view, tree, node);
5993         }
5994       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
5995
5996       if (node == NULL)
5997         break;
5998
5999       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6000           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6001         {
6002           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6003           if (validate_row (tree_view, tree, node, &iter, above_path))
6004             size_changed = TRUE;
6005         }
6006       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6007     }
6008
6009   /* if we scrolled to a path, we need to set the dy here,
6010    * and sync the top row accordingly
6011    */
6012   if (tree_view->priv->scroll_to_path)
6013     {
6014       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6015       gtk_tree_view_top_row_to_dy (tree_view);
6016
6017       need_redraw = TRUE;
6018     }
6019   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6020     {
6021       /* when we are not scrolling, we should never set dy to something
6022        * else than zero. we update top_row to be in sync with dy = 0.
6023        */
6024       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6025       gtk_tree_view_dy_to_top_row (tree_view);
6026     }
6027   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6028     {
6029       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6030       gtk_tree_view_dy_to_top_row (tree_view);
6031     }
6032   else
6033     gtk_tree_view_top_row_to_dy (tree_view);
6034
6035   /* update width/height and queue a resize */
6036   if (size_changed)
6037     {
6038       GtkRequisition requisition;
6039
6040       /* We temporarily guess a size, under the assumption that it will be the
6041        * same when we get our next size_allocate.  If we don't do this, we'll be
6042        * in an inconsistent state if we call top_row_to_dy. */
6043
6044       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6045       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6046       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6047       gtk_adjustment_changed (tree_view->priv->hadjustment);
6048       gtk_adjustment_changed (tree_view->priv->vadjustment);
6049       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6050     }
6051
6052   if (tree_view->priv->scroll_to_path)
6053     {
6054       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6055       tree_view->priv->scroll_to_path = NULL;
6056     }
6057
6058   if (above_path)
6059     gtk_tree_path_free (above_path);
6060
6061   if (tree_view->priv->scroll_to_column)
6062     {
6063       tree_view->priv->scroll_to_column = NULL;
6064     }
6065   if (need_redraw)
6066     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6067 }
6068
6069 static void
6070 initialize_fixed_height_mode (GtkTreeView *tree_view)
6071 {
6072   if (!tree_view->priv->tree)
6073     return;
6074
6075   if (tree_view->priv->fixed_height < 0)
6076     {
6077       GtkTreeIter iter;
6078       GtkTreePath *path;
6079
6080       GtkRBTree *tree = NULL;
6081       GtkRBNode *node = NULL;
6082
6083       tree = tree_view->priv->tree;
6084       node = tree->root;
6085
6086       path = _gtk_tree_view_find_path (tree_view, tree, node);
6087       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6088
6089       validate_row (tree_view, tree, node, &iter, path);
6090
6091       gtk_tree_path_free (path);
6092
6093       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6094     }
6095
6096    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6097                                  tree_view->priv->fixed_height, TRUE);
6098 }
6099
6100 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6101  * the left-most uninvalidated node.  We then try walking right, validating
6102  * nodes.  Once we find a valid node, we repeat the previous process of finding
6103  * the first invalid node.
6104  */
6105
6106 static gboolean
6107 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6108 {
6109   GtkRBTree *tree = NULL;
6110   GtkRBNode *node = NULL;
6111   gboolean validated_area = FALSE;
6112   gint retval = TRUE;
6113   GtkTreePath *path = NULL;
6114   GtkTreeIter iter;
6115   gint i = 0;
6116
6117   gint prev_height = -1;
6118   gboolean fixed_height = TRUE;
6119
6120   g_assert (tree_view);
6121
6122   if (tree_view->priv->tree == NULL)
6123       return FALSE;
6124
6125   if (tree_view->priv->fixed_height_mode)
6126     {
6127       if (tree_view->priv->fixed_height < 0)
6128         initialize_fixed_height_mode (tree_view);
6129
6130       return FALSE;
6131     }
6132
6133   do
6134     {
6135       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6136         {
6137           retval = FALSE;
6138           goto done;
6139         }
6140
6141       if (path != NULL)
6142         {
6143           node = _gtk_rbtree_next (tree, node);
6144           if (node != NULL)
6145             {
6146               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6147               gtk_tree_path_next (path);
6148             }
6149           else
6150             {
6151               gtk_tree_path_free (path);
6152               path = NULL;
6153             }
6154         }
6155
6156       if (path == NULL)
6157         {
6158           tree = tree_view->priv->tree;
6159           node = tree_view->priv->tree->root;
6160
6161           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6162
6163           do
6164             {
6165               if (node->left != tree->nil &&
6166                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6167                 {
6168                   node = node->left;
6169                 }
6170               else if (node->right != tree->nil &&
6171                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6172                 {
6173                   node = node->right;
6174                 }
6175               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6176                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6177                 {
6178                   break;
6179                 }
6180               else if (node->children != NULL)
6181                 {
6182                   tree = node->children;
6183                   node = tree->root;
6184                 }
6185               else
6186                 /* RBTree corruption!  All bad */
6187                 g_assert_not_reached ();
6188             }
6189           while (TRUE);
6190           path = _gtk_tree_view_find_path (tree_view, tree, node);
6191           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6192         }
6193
6194       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6195                        validated_area;
6196
6197       if (!tree_view->priv->fixed_height_check)
6198         {
6199           gint height;
6200
6201           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6202           if (prev_height < 0)
6203             prev_height = height;
6204           else if (prev_height != height)
6205             fixed_height = FALSE;
6206         }
6207
6208       i++;
6209     }
6210   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
6211
6212   if (!tree_view->priv->fixed_height_check)
6213    {
6214      if (fixed_height)
6215        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6216
6217      tree_view->priv->fixed_height_check = 1;
6218    }
6219   
6220  done:
6221   if (validated_area)
6222     {
6223       GtkRequisition requisition;
6224       /* We temporarily guess a size, under the assumption that it will be the
6225        * same when we get our next size_allocate.  If we don't do this, we'll be
6226        * in an inconsistent state when we call top_row_to_dy. */
6227
6228       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6229       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6230       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6231       gtk_adjustment_changed (tree_view->priv->hadjustment);
6232       gtk_adjustment_changed (tree_view->priv->vadjustment);
6233
6234       if (queue_resize)
6235         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6236     }
6237
6238   if (path) gtk_tree_path_free (path);
6239
6240   return retval;
6241 }
6242
6243 static gboolean
6244 validate_rows (GtkTreeView *tree_view)
6245 {
6246   gboolean retval;
6247   
6248   retval = do_validate_rows (tree_view, TRUE);
6249   
6250   if (! retval && tree_view->priv->validate_rows_timer)
6251     {
6252       g_source_remove (tree_view->priv->validate_rows_timer);
6253       tree_view->priv->validate_rows_timer = 0;
6254     }
6255
6256   return retval;
6257 }
6258
6259 static gboolean
6260 validate_rows_handler (GtkTreeView *tree_view)
6261 {
6262   gboolean retval;
6263
6264   retval = do_validate_rows (tree_view, TRUE);
6265   if (! retval && tree_view->priv->validate_rows_timer)
6266     {
6267       g_source_remove (tree_view->priv->validate_rows_timer);
6268       tree_view->priv->validate_rows_timer = 0;
6269     }
6270
6271   return retval;
6272 }
6273
6274 static gboolean
6275 do_presize_handler (GtkTreeView *tree_view)
6276 {
6277   if (tree_view->priv->mark_rows_col_dirty)
6278     {
6279       if (tree_view->priv->tree)
6280         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6281       tree_view->priv->mark_rows_col_dirty = FALSE;
6282     }
6283   validate_visible_area (tree_view);
6284   tree_view->priv->presize_handler_timer = 0;
6285
6286   if (tree_view->priv->fixed_height_mode)
6287     {
6288       GtkRequisition requisition;
6289
6290       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6291
6292       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6293       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6294       gtk_adjustment_changed (tree_view->priv->hadjustment);
6295       gtk_adjustment_changed (tree_view->priv->vadjustment);
6296       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6297     }
6298                    
6299   return FALSE;
6300 }
6301
6302 static gboolean
6303 presize_handler_callback (gpointer data)
6304 {
6305   do_presize_handler (GTK_TREE_VIEW (data));
6306                    
6307   return FALSE;
6308 }
6309
6310 static void
6311 install_presize_handler (GtkTreeView *tree_view)
6312 {
6313   if (! GTK_WIDGET_REALIZED (tree_view))
6314     return;
6315
6316   if (! tree_view->priv->presize_handler_timer)
6317     {
6318       tree_view->priv->presize_handler_timer =
6319         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6320     }
6321   if (! tree_view->priv->validate_rows_timer)
6322     {
6323       tree_view->priv->validate_rows_timer =
6324         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6325     }
6326 }
6327
6328 static gboolean
6329 scroll_sync_handler (GtkTreeView *tree_view)
6330 {
6331   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6332     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6333   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6334     gtk_tree_view_top_row_to_dy (tree_view);
6335   else
6336     gtk_tree_view_dy_to_top_row (tree_view);
6337
6338   tree_view->priv->scroll_sync_timer = 0;
6339
6340   return FALSE;
6341 }
6342
6343 static void
6344 install_scroll_sync_handler (GtkTreeView *tree_view)
6345 {
6346   if (! GTK_WIDGET_REALIZED (tree_view))
6347     return;
6348
6349   if (!tree_view->priv->scroll_sync_timer)
6350     {
6351       tree_view->priv->scroll_sync_timer =
6352         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6353     }
6354 }
6355
6356 static void
6357 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6358                            GtkTreePath *path,
6359                            gint         offset)
6360 {
6361   gtk_tree_row_reference_free (tree_view->priv->top_row);
6362
6363   if (!path)
6364     {
6365       tree_view->priv->top_row = NULL;
6366       tree_view->priv->top_row_dy = 0;
6367     }
6368   else
6369     {
6370       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6371       tree_view->priv->top_row_dy = offset;
6372     }
6373 }
6374
6375 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6376  * it's set to be NULL, and top_row_dy is 0;
6377  */
6378 static void
6379 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6380 {
6381   gint offset;
6382   GtkTreePath *path;
6383   GtkRBTree *tree;
6384   GtkRBNode *node;
6385
6386   if (tree_view->priv->tree == NULL)
6387     {
6388       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6389     }
6390   else
6391     {
6392       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6393                                         tree_view->priv->dy,
6394                                         &tree, &node);
6395
6396       if (tree == NULL)
6397         {
6398           tree_view->priv->top_row = NULL;
6399           tree_view->priv->top_row_dy = 0;
6400         }
6401       else
6402         {
6403           path = _gtk_tree_view_find_path (tree_view, tree, node);
6404           gtk_tree_view_set_top_row (tree_view, path, offset);
6405           gtk_tree_path_free (path);
6406         }
6407     }
6408 }
6409
6410 static void
6411 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6412 {
6413   GtkTreePath *path;
6414   GtkRBTree *tree;
6415   GtkRBNode *node;
6416   int new_dy;
6417
6418   if (tree_view->priv->top_row)
6419     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6420   else
6421     path = NULL;
6422
6423   if (!path)
6424     tree = NULL;
6425   else
6426     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6427
6428   if (path)
6429     gtk_tree_path_free (path);
6430
6431   if (tree == NULL)
6432     {
6433       /* keep dy and set new toprow */
6434       gtk_tree_row_reference_free (tree_view->priv->top_row);
6435       tree_view->priv->top_row = NULL;
6436       tree_view->priv->top_row_dy = 0;
6437       /* DO NOT install the idle handler */
6438       gtk_tree_view_dy_to_top_row (tree_view);
6439       return;
6440     }
6441
6442   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6443       < tree_view->priv->top_row_dy)
6444     {
6445       /* new top row -- do NOT install the idle handler */
6446       gtk_tree_view_dy_to_top_row (tree_view);
6447       return;
6448     }
6449
6450   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6451   new_dy += tree_view->priv->top_row_dy;
6452
6453   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6454     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6455
6456   new_dy = MAX (0, new_dy);
6457
6458   tree_view->priv->in_top_row_to_dy = TRUE;
6459   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6460   tree_view->priv->in_top_row_to_dy = FALSE;
6461 }
6462
6463
6464 void
6465 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6466 {
6467   tree_view->priv->mark_rows_col_dirty = TRUE;
6468
6469   install_presize_handler (tree_view);
6470 }
6471
6472 /*
6473  * This function works synchronously (due to the while (validate_rows...)
6474  * loop).
6475  *
6476  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6477  * here. You now need to check that yourself.
6478  */
6479 void
6480 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6481                                 GtkTreeViewColumn *column)
6482 {
6483   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6484   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6485
6486   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6487
6488   do_presize_handler (tree_view);
6489   while (validate_rows (tree_view));
6490
6491   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6492 }
6493
6494 /* Drag-and-drop */
6495
6496 static void
6497 set_source_row (GdkDragContext *context,
6498                 GtkTreeModel   *model,
6499                 GtkTreePath    *source_row)
6500 {
6501   g_object_set_data_full (G_OBJECT (context),
6502                           I_("gtk-tree-view-source-row"),
6503                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6504                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6505 }
6506
6507 static GtkTreePath*
6508 get_source_row (GdkDragContext *context)
6509 {
6510   GtkTreeRowReference *ref =
6511     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6512
6513   if (ref)
6514     return gtk_tree_row_reference_get_path (ref);
6515   else
6516     return NULL;
6517 }
6518
6519 typedef struct
6520 {
6521   GtkTreeRowReference *dest_row;
6522   guint                path_down_mode   : 1;
6523   guint                empty_view_drop  : 1;
6524   guint                drop_append_mode : 1;
6525 }
6526 DestRow;
6527
6528 static void
6529 dest_row_free (gpointer data)
6530 {
6531   DestRow *dr = (DestRow *)data;
6532
6533   gtk_tree_row_reference_free (dr->dest_row);
6534   g_slice_free (DestRow, dr);
6535 }
6536
6537 static void
6538 set_dest_row (GdkDragContext *context,
6539               GtkTreeModel   *model,
6540               GtkTreePath    *dest_row,
6541               gboolean        path_down_mode,
6542               gboolean        empty_view_drop,
6543               gboolean        drop_append_mode)
6544 {
6545   DestRow *dr;
6546
6547   if (!dest_row)
6548     {
6549       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6550                               NULL, NULL);
6551       return;
6552     }
6553
6554   dr = g_slice_new (DestRow);
6555
6556   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6557   dr->path_down_mode = path_down_mode != FALSE;
6558   dr->empty_view_drop = empty_view_drop != FALSE;
6559   dr->drop_append_mode = drop_append_mode != FALSE;
6560
6561   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6562                           dr, (GDestroyNotify) dest_row_free);
6563 }
6564
6565 static GtkTreePath*
6566 get_dest_row (GdkDragContext *context,
6567               gboolean       *path_down_mode)
6568 {
6569   DestRow *dr =
6570     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6571
6572   if (dr)
6573     {
6574       GtkTreePath *path = NULL;
6575
6576       if (path_down_mode)
6577         *path_down_mode = dr->path_down_mode;
6578
6579       if (dr->dest_row)
6580         path = gtk_tree_row_reference_get_path (dr->dest_row);
6581       else if (dr->empty_view_drop)
6582         path = gtk_tree_path_new_from_indices (0, -1);
6583       else
6584         path = NULL;
6585
6586       if (path && dr->drop_append_mode)
6587         gtk_tree_path_next (path);
6588
6589       return path;
6590     }
6591   else
6592     return NULL;
6593 }
6594
6595 /* Get/set whether drag_motion requested the drag data and
6596  * drag_data_received should thus not actually insert the data,
6597  * since the data doesn't result from a drop.
6598  */
6599 static void
6600 set_status_pending (GdkDragContext *context,
6601                     GdkDragAction   suggested_action)
6602 {
6603   g_object_set_data (G_OBJECT (context),
6604                      I_("gtk-tree-view-status-pending"),
6605                      GINT_TO_POINTER (suggested_action));
6606 }
6607
6608 static GdkDragAction
6609 get_status_pending (GdkDragContext *context)
6610 {
6611   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6612                                              "gtk-tree-view-status-pending"));
6613 }
6614
6615 static TreeViewDragInfo*
6616 get_info (GtkTreeView *tree_view)
6617 {
6618   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6619 }
6620
6621 static void
6622 destroy_info (TreeViewDragInfo *di)
6623 {
6624   g_slice_free (TreeViewDragInfo, di);
6625 }
6626
6627 static TreeViewDragInfo*
6628 ensure_info (GtkTreeView *tree_view)
6629 {
6630   TreeViewDragInfo *di;
6631
6632   di = get_info (tree_view);
6633
6634   if (di == NULL)
6635     {
6636       di = g_slice_new0 (TreeViewDragInfo);
6637
6638       g_object_set_data_full (G_OBJECT (tree_view),
6639                               I_("gtk-tree-view-drag-info"),
6640                               di,
6641                               (GDestroyNotify) destroy_info);
6642     }
6643
6644   return di;
6645 }
6646
6647 static void
6648 remove_info (GtkTreeView *tree_view)
6649 {
6650   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6651 }
6652
6653 #if 0
6654 static gint
6655 drag_scan_timeout (gpointer data)
6656 {
6657   GtkTreeView *tree_view;
6658   gint x, y;
6659   GdkModifierType state;
6660   GtkTreePath *path = NULL;
6661   GtkTreeViewColumn *column = NULL;
6662   GdkRectangle visible_rect;
6663
6664   GDK_THREADS_ENTER ();
6665
6666   tree_view = GTK_TREE_VIEW (data);
6667
6668   gdk_window_get_pointer (tree_view->priv->bin_window,
6669                           &x, &y, &state);
6670
6671   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6672
6673   /* See if we are near the edge. */
6674   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6675       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6676       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6677       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6678     {
6679       gtk_tree_view_get_path_at_pos (tree_view,
6680                                      tree_view->priv->bin_window,
6681                                      x, y,
6682                                      &path,
6683                                      &column,
6684                                      NULL,
6685                                      NULL);
6686
6687       if (path != NULL)
6688         {
6689           gtk_tree_view_scroll_to_cell (tree_view,
6690                                         path,
6691                                         column,
6692                                         TRUE,
6693                                         0.5, 0.5);
6694
6695           gtk_tree_path_free (path);
6696         }
6697     }
6698
6699   GDK_THREADS_LEAVE ();
6700
6701   return TRUE;
6702 }
6703 #endif /* 0 */
6704
6705 static void
6706 add_scroll_timeout (GtkTreeView *tree_view)
6707 {
6708   if (tree_view->priv->scroll_timeout == 0)
6709     {
6710       tree_view->priv->scroll_timeout =
6711         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6712     }
6713 }
6714
6715 static void
6716 remove_scroll_timeout (GtkTreeView *tree_view)
6717 {
6718   if (tree_view->priv->scroll_timeout != 0)
6719     {
6720       g_source_remove (tree_view->priv->scroll_timeout);
6721       tree_view->priv->scroll_timeout = 0;
6722     }
6723 }
6724
6725 static gboolean
6726 check_model_dnd (GtkTreeModel *model,
6727                  GType         required_iface,
6728                  const gchar  *signal)
6729 {
6730   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6731     {
6732       g_warning ("You must override the default '%s' handler "
6733                  "on GtkTreeView when using models that don't support "
6734                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6735                  "is to connect to '%s' and call "
6736                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6737                  "the default handler from running. Look at the source code "
6738                  "for the default handler in gtktreeview.c to get an idea what "
6739                  "your handler should do. (gtktreeview.c is in the GTK source "
6740                  "code.) If you're using GTK from a language other than C, "
6741                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6742                  signal, g_type_name (required_iface), signal);
6743       return FALSE;
6744     }
6745   else
6746     return TRUE;
6747 }
6748
6749 static void
6750 remove_open_timeout (GtkTreeView *tree_view)
6751 {
6752   if (tree_view->priv->open_dest_timeout != 0)
6753     {
6754       g_source_remove (tree_view->priv->open_dest_timeout);
6755       tree_view->priv->open_dest_timeout = 0;
6756     }
6757 }
6758
6759
6760 static gint
6761 open_row_timeout (gpointer data)
6762 {
6763   GtkTreeView *tree_view = data;
6764   GtkTreePath *dest_path = NULL;
6765   GtkTreeViewDropPosition pos;
6766   gboolean result = FALSE;
6767
6768   gtk_tree_view_get_drag_dest_row (tree_view,
6769                                    &dest_path,
6770                                    &pos);
6771
6772   if (dest_path &&
6773       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6774        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6775     {
6776       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6777       tree_view->priv->open_dest_timeout = 0;
6778
6779       gtk_tree_path_free (dest_path);
6780     }
6781   else
6782     {
6783       if (dest_path)
6784         gtk_tree_path_free (dest_path);
6785
6786       result = TRUE;
6787     }
6788
6789   return result;
6790 }
6791
6792 static gboolean
6793 scroll_row_timeout (gpointer data)
6794 {
6795   GtkTreeView *tree_view = data;
6796
6797   gtk_tree_view_vertical_autoscroll (tree_view);
6798
6799   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6800     gtk_tree_view_update_rubber_band (tree_view);
6801
6802   return TRUE;
6803 }
6804
6805 /* Returns TRUE if event should not be propagated to parent widgets */
6806 static gboolean
6807 set_destination_row (GtkTreeView    *tree_view,
6808                      GdkDragContext *context,
6809                      /* coordinates relative to the widget */
6810                      gint            x,
6811                      gint            y,
6812                      GdkDragAction  *suggested_action,
6813                      GdkAtom        *target)
6814 {
6815   GtkTreePath *path = NULL;
6816   GtkTreeViewDropPosition pos;
6817   GtkTreeViewDropPosition old_pos;
6818   TreeViewDragInfo *di;
6819   GtkWidget *widget;
6820   GtkTreePath *old_dest_path = NULL;
6821   gboolean can_drop = FALSE;
6822
6823   *suggested_action = 0;
6824   *target = GDK_NONE;
6825
6826   widget = GTK_WIDGET (tree_view);
6827
6828   di = get_info (tree_view);
6829
6830   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6831     {
6832       /* someone unset us as a drag dest, note that if
6833        * we return FALSE drag_leave isn't called
6834        */
6835
6836       gtk_tree_view_set_drag_dest_row (tree_view,
6837                                        NULL,
6838                                        GTK_TREE_VIEW_DROP_BEFORE);
6839
6840       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6841       remove_open_timeout (GTK_TREE_VIEW (widget));
6842
6843       return FALSE; /* no longer a drop site */
6844     }
6845
6846   *target = gtk_drag_dest_find_target (widget, context,
6847                                        gtk_drag_dest_get_target_list (widget));
6848   if (*target == GDK_NONE)
6849     {
6850       return FALSE;
6851     }
6852
6853   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6854                                           x, y,
6855                                           &path,
6856                                           &pos))
6857     {
6858       gint n_children;
6859       GtkTreeModel *model;
6860
6861       remove_open_timeout (tree_view);
6862
6863       /* the row got dropped on empty space, let's setup a special case
6864        */
6865
6866       if (path)
6867         gtk_tree_path_free (path);
6868
6869       model = gtk_tree_view_get_model (tree_view);
6870
6871       n_children = gtk_tree_model_iter_n_children (model, NULL);
6872       if (n_children)
6873         {
6874           pos = GTK_TREE_VIEW_DROP_AFTER;
6875           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6876         }
6877       else
6878         {
6879           pos = GTK_TREE_VIEW_DROP_BEFORE;
6880           path = gtk_tree_path_new_from_indices (0, -1);
6881         }
6882
6883       can_drop = TRUE;
6884
6885       goto out;
6886     }
6887
6888   g_assert (path);
6889
6890   /* If we left the current row's "open" zone, unset the timeout for
6891    * opening the row
6892    */
6893   gtk_tree_view_get_drag_dest_row (tree_view,
6894                                    &old_dest_path,
6895                                    &old_pos);
6896
6897   if (old_dest_path &&
6898       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6899        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6900          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6901     remove_open_timeout (tree_view);
6902
6903   if (old_dest_path)
6904     gtk_tree_path_free (old_dest_path);
6905
6906   if (TRUE /* FIXME if the location droppable predicate */)
6907     {
6908       can_drop = TRUE;
6909     }
6910
6911 out:
6912   if (can_drop)
6913     {
6914       GtkWidget *source_widget;
6915
6916       *suggested_action = context->suggested_action;
6917       source_widget = gtk_drag_get_source_widget (context);
6918
6919       if (source_widget == widget)
6920         {
6921           /* Default to MOVE, unless the user has
6922            * pressed ctrl or shift to affect available actions
6923            */
6924           if ((context->actions & GDK_ACTION_MOVE) != 0)
6925             *suggested_action = GDK_ACTION_MOVE;
6926         }
6927
6928       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6929                                        path, pos);
6930     }
6931   else
6932     {
6933       /* can't drop here */
6934       remove_open_timeout (tree_view);
6935
6936       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6937                                        NULL,
6938                                        GTK_TREE_VIEW_DROP_BEFORE);
6939     }
6940
6941   if (path)
6942     gtk_tree_path_free (path);
6943
6944   return TRUE;
6945 }
6946
6947 static GtkTreePath*
6948 get_logical_dest_row (GtkTreeView *tree_view,
6949                       gboolean    *path_down_mode,
6950                       gboolean    *drop_append_mode)
6951 {
6952   /* adjust path to point to the row the drop goes in front of */
6953   GtkTreePath *path = NULL;
6954   GtkTreeViewDropPosition pos;
6955
6956   g_return_val_if_fail (path_down_mode != NULL, NULL);
6957   g_return_val_if_fail (drop_append_mode != NULL, NULL);
6958
6959   *path_down_mode = FALSE;
6960   *drop_append_mode = 0;
6961
6962   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6963
6964   if (path == NULL)
6965     return NULL;
6966
6967   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6968     ; /* do nothing */
6969   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6970            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6971     *path_down_mode = TRUE;
6972   else
6973     {
6974       GtkTreeIter iter;
6975       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
6976
6977       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6978
6979       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6980           !gtk_tree_model_iter_next (model, &iter))
6981         *drop_append_mode = 1;
6982       else
6983         {
6984           *drop_append_mode = 0;
6985           gtk_tree_path_next (path);
6986         }
6987     }
6988
6989   return path;
6990 }
6991
6992 static gboolean
6993 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
6994                                         GdkEventMotion   *event)
6995 {
6996   GtkWidget *widget = GTK_WIDGET (tree_view);
6997   GdkDragContext *context;
6998   TreeViewDragInfo *di;
6999   GtkTreePath *path = NULL;
7000   gint button;
7001   gint cell_x, cell_y;
7002   GtkTreeModel *model;
7003   gboolean retval = FALSE;
7004
7005   di = get_info (tree_view);
7006
7007   if (di == NULL || !di->source_set)
7008     goto out;
7009
7010   if (tree_view->priv->pressed_button < 0)
7011     goto out;
7012
7013   if (!gtk_drag_check_threshold (widget,
7014                                  tree_view->priv->press_start_x,
7015                                  tree_view->priv->press_start_y,
7016                                  event->x, event->y))
7017     goto out;
7018
7019   model = gtk_tree_view_get_model (tree_view);
7020
7021   if (model == NULL)
7022     goto out;
7023
7024   button = tree_view->priv->pressed_button;
7025   tree_view->priv->pressed_button = -1;
7026
7027   gtk_tree_view_get_path_at_pos (tree_view,
7028                                  tree_view->priv->press_start_x,
7029                                  tree_view->priv->press_start_y,
7030                                  &path,
7031                                  NULL,
7032                                  &cell_x,
7033                                  &cell_y);
7034
7035   if (path == NULL)
7036     goto out;
7037
7038   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7039       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7040                                            path))
7041     goto out;
7042
7043   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7044     goto out;
7045
7046   /* Now we can begin the drag */
7047
7048   retval = TRUE;
7049
7050   context = gtk_drag_begin (widget,
7051                             gtk_drag_source_get_target_list (widget),
7052                             di->source_actions,
7053                             button,
7054                             (GdkEvent*)event);
7055
7056   set_source_row (context, model, path);
7057
7058  out:
7059   if (path)
7060     gtk_tree_path_free (path);
7061
7062   return retval;
7063 }
7064
7065
7066 static void
7067 gtk_tree_view_drag_begin (GtkWidget      *widget,
7068                           GdkDragContext *context)
7069 {
7070   GtkTreeView *tree_view;
7071   GtkTreePath *path = NULL;
7072   gint cell_x, cell_y;
7073   GdkPixmap *row_pix;
7074   TreeViewDragInfo *di;
7075
7076   tree_view = GTK_TREE_VIEW (widget);
7077
7078   /* if the user uses a custom DND source impl, we don't set the icon here */
7079   di = get_info (tree_view);
7080
7081   if (di == NULL || !di->source_set)
7082     return;
7083
7084   gtk_tree_view_get_path_at_pos (tree_view,
7085                                  tree_view->priv->press_start_x,
7086                                  tree_view->priv->press_start_y,
7087                                  &path,
7088                                  NULL,
7089                                  &cell_x,
7090                                  &cell_y);
7091
7092   g_return_if_fail (path != NULL);
7093
7094   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7095                                                 path);
7096
7097   gtk_drag_set_icon_pixmap (context,
7098                             gdk_drawable_get_colormap (row_pix),
7099                             row_pix,
7100                             NULL,
7101                             /* the + 1 is for the black border in the icon */
7102                             tree_view->priv->press_start_x + 1,
7103                             cell_y + 1);
7104
7105   g_object_unref (row_pix);
7106   gtk_tree_path_free (path);
7107 }
7108
7109 static void
7110 gtk_tree_view_drag_end (GtkWidget      *widget,
7111                         GdkDragContext *context)
7112 {
7113   /* do nothing */
7114 }
7115
7116 /* Default signal implementations for the drag signals */
7117 static void
7118 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7119                              GdkDragContext   *context,
7120                              GtkSelectionData *selection_data,
7121                              guint             info,
7122                              guint             time)
7123 {
7124   GtkTreeView *tree_view;
7125   GtkTreeModel *model;
7126   TreeViewDragInfo *di;
7127   GtkTreePath *source_row;
7128
7129   tree_view = GTK_TREE_VIEW (widget);
7130
7131   model = gtk_tree_view_get_model (tree_view);
7132
7133   if (model == NULL)
7134     return;
7135
7136   di = get_info (GTK_TREE_VIEW (widget));
7137
7138   if (di == NULL)
7139     return;
7140
7141   source_row = get_source_row (context);
7142
7143   if (source_row == NULL)
7144     return;
7145
7146   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7147    * any model; for DragSource models there are some other targets
7148    * we also support.
7149    */
7150
7151   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7152       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7153                                           source_row,
7154                                           selection_data))
7155     goto done;
7156
7157   /* If drag_data_get does nothing, try providing row data. */
7158   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7159     {
7160       gtk_tree_set_row_drag_data (selection_data,
7161                                   model,
7162                                   source_row);
7163     }
7164
7165  done:
7166   gtk_tree_path_free (source_row);
7167 }
7168
7169
7170 static void
7171 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7172                                 GdkDragContext *context)
7173 {
7174   TreeViewDragInfo *di;
7175   GtkTreeModel *model;
7176   GtkTreeView *tree_view;
7177   GtkTreePath *source_row;
7178
7179   tree_view = GTK_TREE_VIEW (widget);
7180   model = gtk_tree_view_get_model (tree_view);
7181
7182   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7183     return;
7184
7185   di = get_info (tree_view);
7186
7187   if (di == NULL)
7188     return;
7189
7190   source_row = get_source_row (context);
7191
7192   if (source_row == NULL)
7193     return;
7194
7195   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7196                                          source_row);
7197
7198   gtk_tree_path_free (source_row);
7199
7200   set_source_row (context, NULL, NULL);
7201 }
7202
7203 static void
7204 gtk_tree_view_drag_leave (GtkWidget      *widget,
7205                           GdkDragContext *context,
7206                           guint             time)
7207 {
7208   /* unset any highlight row */
7209   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7210                                    NULL,
7211                                    GTK_TREE_VIEW_DROP_BEFORE);
7212
7213   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7214   remove_open_timeout (GTK_TREE_VIEW (widget));
7215 }
7216
7217
7218 static gboolean
7219 gtk_tree_view_drag_motion (GtkWidget        *widget,
7220                            GdkDragContext   *context,
7221                            /* coordinates relative to the widget */
7222                            gint              x,
7223                            gint              y,
7224                            guint             time)
7225 {
7226   gboolean empty;
7227   GtkTreePath *path = NULL;
7228   GtkTreeViewDropPosition pos;
7229   GtkTreeView *tree_view;
7230   GdkDragAction suggested_action = 0;
7231   GdkAtom target;
7232
7233   tree_view = GTK_TREE_VIEW (widget);
7234
7235   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7236     return FALSE;
7237
7238   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7239
7240   /* we only know this *after* set_desination_row */
7241   empty = tree_view->priv->empty_view_drop;
7242
7243   if (path == NULL && !empty)
7244     {
7245       /* Can't drop here. */
7246       gdk_drag_status (context, 0, time);
7247     }
7248   else
7249     {
7250       if (tree_view->priv->open_dest_timeout == 0 &&
7251           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7252            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7253         {
7254           tree_view->priv->open_dest_timeout =
7255             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7256         }
7257       else
7258         {
7259           add_scroll_timeout (tree_view);
7260         }
7261
7262       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7263         {
7264           /* Request data so we can use the source row when
7265            * determining whether to accept the drop
7266            */
7267           set_status_pending (context, suggested_action);
7268           gtk_drag_get_data (widget, context, target, time);
7269         }
7270       else
7271         {
7272           set_status_pending (context, 0);
7273           gdk_drag_status (context, suggested_action, time);
7274         }
7275     }
7276
7277   if (path)
7278     gtk_tree_path_free (path);
7279
7280   return TRUE;
7281 }
7282
7283
7284 static gboolean
7285 gtk_tree_view_drag_drop (GtkWidget        *widget,
7286                          GdkDragContext   *context,
7287                          /* coordinates relative to the widget */
7288                          gint              x,
7289                          gint              y,
7290                          guint             time)
7291 {
7292   GtkTreeView *tree_view;
7293   GtkTreePath *path;
7294   GdkDragAction suggested_action = 0;
7295   GdkAtom target = GDK_NONE;
7296   TreeViewDragInfo *di;
7297   GtkTreeModel *model;
7298   gboolean path_down_mode;
7299   gboolean drop_append_mode;
7300
7301   tree_view = GTK_TREE_VIEW (widget);
7302
7303   model = gtk_tree_view_get_model (tree_view);
7304
7305   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7306   remove_open_timeout (GTK_TREE_VIEW (widget));
7307
7308   di = get_info (tree_view);
7309
7310   if (di == NULL)
7311     return FALSE;
7312
7313   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7314     return FALSE;
7315
7316   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7317     return FALSE;
7318
7319   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7320
7321   if (target != GDK_NONE && path != NULL)
7322     {
7323       /* in case a motion had requested drag data, change things so we
7324        * treat drag data receives as a drop.
7325        */
7326       set_status_pending (context, 0);
7327       set_dest_row (context, model, path,
7328                     path_down_mode, tree_view->priv->empty_view_drop,
7329                     drop_append_mode);
7330     }
7331
7332   if (path)
7333     gtk_tree_path_free (path);
7334
7335   /* Unset this thing */
7336   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7337                                    NULL,
7338                                    GTK_TREE_VIEW_DROP_BEFORE);
7339
7340   if (target != GDK_NONE)
7341     {
7342       gtk_drag_get_data (widget, context, target, time);
7343       return TRUE;
7344     }
7345   else
7346     return FALSE;
7347 }
7348
7349 static void
7350 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7351                                   GdkDragContext   *context,
7352                                   /* coordinates relative to the widget */
7353                                   gint              x,
7354                                   gint              y,
7355                                   GtkSelectionData *selection_data,
7356                                   guint             info,
7357                                   guint             time)
7358 {
7359   GtkTreePath *path;
7360   TreeViewDragInfo *di;
7361   gboolean accepted = FALSE;
7362   GtkTreeModel *model;
7363   GtkTreeView *tree_view;
7364   GtkTreePath *dest_row;
7365   GdkDragAction suggested_action;
7366   gboolean path_down_mode;
7367   gboolean drop_append_mode;
7368
7369   tree_view = GTK_TREE_VIEW (widget);
7370
7371   model = gtk_tree_view_get_model (tree_view);
7372
7373   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7374     return;
7375
7376   di = get_info (tree_view);
7377
7378   if (di == NULL)
7379     return;
7380
7381   suggested_action = get_status_pending (context);
7382
7383   if (suggested_action)
7384     {
7385       /* We are getting this data due to a request in drag_motion,
7386        * rather than due to a request in drag_drop, so we are just
7387        * supposed to call drag_status, not actually paste in the
7388        * data.
7389        */
7390       path = get_logical_dest_row (tree_view, &path_down_mode,
7391                                    &drop_append_mode);
7392
7393       if (path == NULL)
7394         suggested_action = 0;
7395       else if (path_down_mode)
7396         gtk_tree_path_down (path);
7397
7398       if (suggested_action)
7399         {
7400           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7401                                                      path,
7402                                                      selection_data))
7403             {
7404               if (path_down_mode)
7405                 {
7406                   path_down_mode = FALSE;
7407                   gtk_tree_path_up (path);
7408
7409                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7410                                                              path,
7411                                                              selection_data))
7412                     suggested_action = 0;
7413                 }
7414               else
7415                 suggested_action = 0;
7416             }
7417         }
7418
7419       gdk_drag_status (context, suggested_action, time);
7420
7421       if (path)
7422         gtk_tree_path_free (path);
7423
7424       /* If you can't drop, remove user drop indicator until the next motion */
7425       if (suggested_action == 0)
7426         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7427                                          NULL,
7428                                          GTK_TREE_VIEW_DROP_BEFORE);
7429
7430       return;
7431     }
7432
7433   dest_row = get_dest_row (context, &path_down_mode);
7434
7435   if (dest_row == NULL)
7436     return;
7437
7438   if (selection_data->length >= 0)
7439     {
7440       if (path_down_mode)
7441         {
7442           gtk_tree_path_down (dest_row);
7443           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7444                                                      dest_row, selection_data))
7445             gtk_tree_path_up (dest_row);
7446         }
7447     }
7448
7449   if (selection_data->length >= 0)
7450     {
7451       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7452                                                  dest_row,
7453                                                  selection_data))
7454         accepted = TRUE;
7455     }
7456
7457   gtk_drag_finish (context,
7458                    accepted,
7459                    (context->action == GDK_ACTION_MOVE),
7460                    time);
7461
7462   if (gtk_tree_path_get_depth (dest_row) == 1
7463       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7464     {
7465       /* special special case drag to "0", scroll to first item */
7466       if (!tree_view->priv->scroll_to_path)
7467         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7468     }
7469
7470   gtk_tree_path_free (dest_row);
7471
7472   /* drop dest_row */
7473   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7474 }
7475
7476
7477
7478 /* GtkContainer Methods
7479  */
7480
7481
7482 static void
7483 gtk_tree_view_remove (GtkContainer *container,
7484                       GtkWidget    *widget)
7485 {
7486   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7487   GtkTreeViewChild *child = NULL;
7488   GList *tmp_list;
7489
7490   tmp_list = tree_view->priv->children;
7491   while (tmp_list)
7492     {
7493       child = tmp_list->data;
7494       if (child->widget == widget)
7495         {
7496           gtk_widget_unparent (widget);
7497
7498           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7499           g_list_free_1 (tmp_list);
7500           g_slice_free (GtkTreeViewChild, child);
7501           return;
7502         }
7503
7504       tmp_list = tmp_list->next;
7505     }
7506
7507   tmp_list = tree_view->priv->columns;
7508
7509   while (tmp_list)
7510     {
7511       GtkTreeViewColumn *column;
7512       column = tmp_list->data;
7513       if (column->button == widget)
7514         {
7515           gtk_widget_unparent (widget);
7516           return;
7517         }
7518       tmp_list = tmp_list->next;
7519     }
7520 }
7521
7522 static void
7523 gtk_tree_view_forall (GtkContainer *container,
7524                       gboolean      include_internals,
7525                       GtkCallback   callback,
7526                       gpointer      callback_data)
7527 {
7528   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7529   GtkTreeViewChild *child = NULL;
7530   GtkTreeViewColumn *column;
7531   GList *tmp_list;
7532
7533   tmp_list = tree_view->priv->children;
7534   while (tmp_list)
7535     {
7536       child = tmp_list->data;
7537       tmp_list = tmp_list->next;
7538
7539       (* callback) (child->widget, callback_data);
7540     }
7541   if (include_internals == FALSE)
7542     return;
7543
7544   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7545     {
7546       column = tmp_list->data;
7547
7548       if (column->button)
7549         (* callback) (column->button, callback_data);
7550     }
7551 }
7552
7553 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7554  * cells. If so we draw one big row-spanning focus rectangle.
7555  */
7556 static gboolean
7557 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7558 {
7559   GList *list;
7560
7561   for (list = tree_view->priv->columns; list; list = list->next)
7562     {
7563       if (!((GtkTreeViewColumn *)list->data)->visible)
7564         continue;
7565       if (_gtk_tree_view_column_count_special_cells (list->data))
7566         return TRUE;
7567     }
7568
7569   return FALSE;
7570 }
7571
7572 static void
7573 column_sizing_notify (GObject    *object,
7574                       GParamSpec *pspec,
7575                       gpointer    data)
7576 {
7577   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7578
7579   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7580     /* disable fixed height mode */
7581     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7582 }
7583
7584 /**
7585  * gtk_tree_view_set_fixed_height_mode:
7586  * @tree_view: a #GtkTreeView 
7587  * @enable: %TRUE to enable fixed height mode
7588  * 
7589  * Enables or disables the fixed height mode of @tree_view. 
7590  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7591  * rows have the same height. 
7592  * Only enable this option if all rows are the same height and all
7593  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7594  *
7595  * Since: 2.6 
7596  **/
7597 void
7598 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7599                                      gboolean     enable)
7600 {
7601   GList *l;
7602   
7603   enable = enable != FALSE;
7604
7605   if (enable == tree_view->priv->fixed_height_mode)
7606     return;
7607
7608   if (!enable)
7609     {
7610       tree_view->priv->fixed_height_mode = 0;
7611       tree_view->priv->fixed_height = -1;
7612
7613       /* force a revalidation */
7614       install_presize_handler (tree_view);
7615     }
7616   else 
7617     {
7618       /* make sure all columns are of type FIXED */
7619       for (l = tree_view->priv->columns; l; l = l->next)
7620         {
7621           GtkTreeViewColumn *c = l->data;
7622           
7623           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7624         }
7625       
7626       /* yes, we really have to do this is in a separate loop */
7627       for (l = tree_view->priv->columns; l; l = l->next)
7628         g_signal_connect (l->data, "notify::sizing",
7629                           G_CALLBACK (column_sizing_notify), tree_view);
7630       
7631       tree_view->priv->fixed_height_mode = 1;
7632       tree_view->priv->fixed_height = -1;
7633       
7634       if (tree_view->priv->tree)
7635         initialize_fixed_height_mode (tree_view);
7636     }
7637
7638   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7639 }
7640
7641 /**
7642  * gtk_tree_view_get_fixed_height_mode:
7643  * @tree_view: a #GtkTreeView
7644  * 
7645  * Returns whether fixed height mode is turned on for @tree_view.
7646  * 
7647  * Return value: %TRUE if @tree_view is in fixed height mode
7648  * 
7649  * Since: 2.6
7650  **/
7651 gboolean
7652 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7653 {
7654   return tree_view->priv->fixed_height_mode;
7655 }
7656
7657 /* Returns TRUE if the focus is within the headers, after the focus operation is
7658  * done
7659  */
7660 static gboolean
7661 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7662                             GtkDirectionType  dir,
7663                             gboolean          clamp_column_visible)
7664 {
7665   GtkWidget *focus_child;
7666
7667   GList *last_column, *first_column;
7668   GList *tmp_list;
7669   gboolean rtl;
7670
7671   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7672     return FALSE;
7673
7674   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7675
7676   first_column = tree_view->priv->columns;
7677   while (first_column)
7678     {
7679       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7680           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7681           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7682            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7683         break;
7684       first_column = first_column->next;
7685     }
7686
7687   /* No headers are visible, or are focusable.  We can't focus in or out.
7688    */
7689   if (first_column == NULL)
7690     return FALSE;
7691
7692   last_column = g_list_last (tree_view->priv->columns);
7693   while (last_column)
7694     {
7695       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7696           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7697           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7698            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7699         break;
7700       last_column = last_column->prev;
7701     }
7702
7703
7704   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7705
7706   switch (dir)
7707     {
7708     case GTK_DIR_TAB_BACKWARD:
7709     case GTK_DIR_TAB_FORWARD:
7710     case GTK_DIR_UP:
7711     case GTK_DIR_DOWN:
7712       if (focus_child == NULL)
7713         {
7714           if (tree_view->priv->focus_column != NULL && GTK_WIDGET_CAN_FOCUS (tree_view->priv->focus_column->button))
7715             focus_child = tree_view->priv->focus_column->button;
7716           else
7717             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7718           gtk_widget_grab_focus (focus_child);
7719           break;
7720         }
7721       return FALSE;
7722
7723     case GTK_DIR_LEFT:
7724     case GTK_DIR_RIGHT:
7725       if (focus_child == NULL)
7726         {
7727           if (tree_view->priv->focus_column != NULL)
7728             focus_child = tree_view->priv->focus_column->button;
7729           else if (dir == GTK_DIR_LEFT)
7730             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7731           else
7732             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7733           gtk_widget_grab_focus (focus_child);
7734           break;
7735         }
7736
7737       if (gtk_widget_child_focus (focus_child, dir))
7738         {
7739           /* The focus moves inside the button. */
7740           /* This is probably a great example of bad UI */
7741           break;
7742         }
7743
7744       /* We need to move the focus among the row of buttons. */
7745       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7746         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7747           break;
7748
7749       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7750           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7751         {
7752           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7753           break;
7754         }
7755
7756       while (tmp_list)
7757         {
7758           GtkTreeViewColumn *column;
7759
7760           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7761             tmp_list = tmp_list->next;
7762           else
7763             tmp_list = tmp_list->prev;
7764
7765           if (tmp_list == NULL)
7766             {
7767               g_warning ("Internal button not found");
7768               break;
7769             }
7770           column = tmp_list->data;
7771           if (column->button &&
7772               column->visible &&
7773               GTK_WIDGET_CAN_FOCUS (column->button))
7774             {
7775               focus_child = column->button;
7776               gtk_widget_grab_focus (column->button);
7777               break;
7778             }
7779         }
7780       break;
7781     default:
7782       g_assert_not_reached ();
7783       break;
7784     }
7785
7786   /* if focus child is non-null, we assume it's been set to the current focus child
7787    */
7788   if (focus_child)
7789     {
7790       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7791         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7792           {
7793             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7794             break;
7795           }
7796
7797       if (clamp_column_visible)
7798         {
7799           gtk_tree_view_clamp_column_visible (tree_view,
7800                                               tree_view->priv->focus_column,
7801                                               FALSE);
7802         }
7803     }
7804
7805   return (focus_child != NULL);
7806 }
7807
7808 /* This function returns in 'path' the first focusable path, if the given path
7809  * is already focusable, it's the returned one.
7810  */
7811 static gboolean
7812 search_first_focusable_path (GtkTreeView  *tree_view,
7813                              GtkTreePath **path,
7814                              gboolean      search_forward,
7815                              GtkRBTree   **new_tree,
7816                              GtkRBNode   **new_node)
7817 {
7818   GtkRBTree *tree = NULL;
7819   GtkRBNode *node = NULL;
7820
7821   if (!path || !*path)
7822     return FALSE;
7823
7824   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7825
7826   if (!tree || !node)
7827     return FALSE;
7828
7829   while (node && row_is_separator (tree_view, NULL, *path))
7830     {
7831       if (search_forward)
7832         _gtk_rbtree_next_full (tree, node, &tree, &node);
7833       else
7834         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7835
7836       if (*path)
7837         gtk_tree_path_free (*path);
7838
7839       if (node)
7840         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7841       else
7842         *path = NULL;
7843     }
7844
7845   if (new_tree)
7846     *new_tree = tree;
7847
7848   if (new_node)
7849     *new_node = node;
7850
7851   return (*path != NULL);
7852 }
7853
7854 static gint
7855 gtk_tree_view_focus (GtkWidget        *widget,
7856                      GtkDirectionType  direction)
7857 {
7858   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7859   GtkContainer *container = GTK_CONTAINER (widget);
7860   GtkWidget *focus_child;
7861
7862   if (!GTK_WIDGET_IS_SENSITIVE (container) || !GTK_WIDGET_CAN_FOCUS (widget))
7863     return FALSE;
7864
7865   focus_child = container->focus_child;
7866
7867   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7868   /* Case 1.  Headers currently have focus. */
7869   if (focus_child)
7870     {
7871       switch (direction)
7872         {
7873         case GTK_DIR_LEFT:
7874         case GTK_DIR_RIGHT:
7875           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7876           return TRUE;
7877         case GTK_DIR_TAB_BACKWARD:
7878         case GTK_DIR_UP:
7879           return FALSE;
7880         case GTK_DIR_TAB_FORWARD:
7881         case GTK_DIR_DOWN:
7882           gtk_widget_grab_focus (widget);
7883           return TRUE;
7884         default:
7885           g_assert_not_reached ();
7886           return FALSE;
7887         }
7888     }
7889
7890   /* Case 2. We don't have focus at all. */
7891   if (!GTK_WIDGET_HAS_FOCUS (container))
7892     {
7893       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
7894         gtk_widget_grab_focus (widget);
7895       return TRUE;
7896     }
7897
7898   /* Case 3. We have focus already. */
7899   if (direction == GTK_DIR_TAB_BACKWARD)
7900     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
7901   else if (direction == GTK_DIR_TAB_FORWARD)
7902     return FALSE;
7903
7904   /* Other directions caught by the keybindings */
7905   gtk_widget_grab_focus (widget);
7906   return TRUE;
7907 }
7908
7909 static void
7910 gtk_tree_view_grab_focus (GtkWidget *widget)
7911 {
7912   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
7913
7914   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
7915 }
7916
7917 static void
7918 gtk_tree_view_style_set (GtkWidget *widget,
7919                          GtkStyle *previous_style)
7920 {
7921   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7922   GList *list;
7923   GtkTreeViewColumn *column;
7924
7925   if (GTK_WIDGET_REALIZED (widget))
7926     {
7927       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
7928       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
7929       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
7930
7931       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
7932       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
7933     }
7934
7935   gtk_widget_style_get (widget,
7936                         "expander-size", &tree_view->priv->expander_size,
7937                         NULL);
7938   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
7939
7940   for (list = tree_view->priv->columns; list; list = list->next)
7941     {
7942       column = list->data;
7943       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7944     }
7945
7946   tree_view->priv->fixed_height = -1;
7947   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
7948
7949   gtk_widget_queue_resize (widget);
7950 }
7951
7952
7953 static void
7954 gtk_tree_view_set_focus_child (GtkContainer *container,
7955                                GtkWidget    *child)
7956 {
7957   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7958   GList *list;
7959
7960   for (list = tree_view->priv->columns; list; list = list->next)
7961     {
7962       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
7963         {
7964           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
7965           break;
7966         }
7967     }
7968
7969   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
7970 }
7971
7972 static void
7973 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
7974                                GtkAdjustment *hadj,
7975                                GtkAdjustment *vadj)
7976 {
7977   gboolean need_adjust = FALSE;
7978
7979   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7980
7981   if (hadj)
7982     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7983   else
7984     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7985   if (vadj)
7986     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7987   else
7988     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7989
7990   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
7991     {
7992       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
7993                                             gtk_tree_view_adjustment_changed,
7994                                             tree_view);
7995       g_object_unref (tree_view->priv->hadjustment);
7996     }
7997
7998   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
7999     {
8000       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8001                                             gtk_tree_view_adjustment_changed,
8002                                             tree_view);
8003       g_object_unref (tree_view->priv->vadjustment);
8004     }
8005
8006   if (tree_view->priv->hadjustment != hadj)
8007     {
8008       tree_view->priv->hadjustment = hadj;
8009       g_object_ref_sink (tree_view->priv->hadjustment);
8010
8011       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8012                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8013                         tree_view);
8014       need_adjust = TRUE;
8015     }
8016
8017   if (tree_view->priv->vadjustment != vadj)
8018     {
8019       tree_view->priv->vadjustment = vadj;
8020       g_object_ref_sink (tree_view->priv->vadjustment);
8021
8022       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8023                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8024                         tree_view);
8025       need_adjust = TRUE;
8026     }
8027
8028   if (need_adjust)
8029     gtk_tree_view_adjustment_changed (NULL, tree_view);
8030 }
8031
8032
8033 static gboolean
8034 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8035                                 GtkMovementStep    step,
8036                                 gint               count)
8037 {
8038   GdkModifierType state;
8039
8040   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8041   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8042                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8043                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8044                         step == GTK_MOVEMENT_PAGES ||
8045                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8046
8047   if (tree_view->priv->tree == NULL)
8048     return FALSE;
8049   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8050     return FALSE;
8051
8052   gtk_tree_view_stop_editing (tree_view, FALSE);
8053   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8054   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8055
8056   if (gtk_get_current_event_state (&state))
8057     {
8058       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8059         tree_view->priv->ctrl_pressed = TRUE;
8060       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8061         tree_view->priv->shift_pressed = TRUE;
8062     }
8063   /* else we assume not pressed */
8064
8065   switch (step)
8066     {
8067       /* currently we make no distinction.  When we go bi-di, we need to */
8068     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8069     case GTK_MOVEMENT_VISUAL_POSITIONS:
8070       gtk_tree_view_move_cursor_left_right (tree_view, count);
8071       break;
8072     case GTK_MOVEMENT_DISPLAY_LINES:
8073       gtk_tree_view_move_cursor_up_down (tree_view, count);
8074       break;
8075     case GTK_MOVEMENT_PAGES:
8076       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8077       break;
8078     case GTK_MOVEMENT_BUFFER_ENDS:
8079       gtk_tree_view_move_cursor_start_end (tree_view, count);
8080       break;
8081     default:
8082       g_assert_not_reached ();
8083     }
8084
8085   tree_view->priv->ctrl_pressed = FALSE;
8086   tree_view->priv->shift_pressed = FALSE;
8087
8088   return TRUE;
8089 }
8090
8091 static void
8092 gtk_tree_view_put (GtkTreeView *tree_view,
8093                    GtkWidget   *child_widget,
8094                    /* in bin_window coordinates */
8095                    gint         x,
8096                    gint         y,
8097                    gint         width,
8098                    gint         height)
8099 {
8100   GtkTreeViewChild *child;
8101   
8102   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8103   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8104
8105   child = g_slice_new (GtkTreeViewChild);
8106
8107   child->widget = child_widget;
8108   child->x = x;
8109   child->y = y;
8110   child->width = width;
8111   child->height = height;
8112
8113   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8114
8115   if (GTK_WIDGET_REALIZED (tree_view))
8116     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8117   
8118   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8119 }
8120
8121 void
8122 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8123                                   GtkWidget   *widget,
8124                                   /* in tree coordinates */
8125                                   gint         x,
8126                                   gint         y,
8127                                   gint         width,
8128                                   gint         height)
8129 {
8130   GtkTreeViewChild *child = NULL;
8131   GList *list;
8132   GdkRectangle allocation;
8133
8134   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8135   g_return_if_fail (GTK_IS_WIDGET (widget));
8136
8137   for (list = tree_view->priv->children; list; list = list->next)
8138     {
8139       if (((GtkTreeViewChild *)list->data)->widget == widget)
8140         {
8141           child = list->data;
8142           break;
8143         }
8144     }
8145   if (child == NULL)
8146     return;
8147
8148   allocation.x = child->x = x;
8149   allocation.y = child->y = y;
8150   allocation.width = child->width = width;
8151   allocation.height = child->height = height;
8152
8153   if (GTK_WIDGET_REALIZED (widget))
8154     gtk_widget_size_allocate (widget, &allocation);
8155 }
8156
8157
8158 /* TreeModel Callbacks
8159  */
8160
8161 static void
8162 gtk_tree_view_row_changed (GtkTreeModel *model,
8163                            GtkTreePath  *path,
8164                            GtkTreeIter  *iter,
8165                            gpointer      data)
8166 {
8167   GtkTreeView *tree_view = (GtkTreeView *)data;
8168   GtkRBTree *tree;
8169   GtkRBNode *node;
8170   gboolean free_path = FALSE;
8171   GList *list;
8172   GtkTreePath *cursor_path;
8173
8174   g_return_if_fail (path != NULL || iter != NULL);
8175
8176   if (tree_view->priv->cursor != NULL)
8177     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8178   else
8179     cursor_path = NULL;
8180
8181   if (tree_view->priv->edited_column &&
8182       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8183     gtk_tree_view_stop_editing (tree_view, TRUE);
8184
8185   if (cursor_path != NULL)
8186     gtk_tree_path_free (cursor_path);
8187
8188   if (path == NULL)
8189     {
8190       path = gtk_tree_model_get_path (model, iter);
8191       free_path = TRUE;
8192     }
8193   else if (iter == NULL)
8194     gtk_tree_model_get_iter (model, iter, path);
8195
8196   if (_gtk_tree_view_find_node (tree_view,
8197                                 path,
8198                                 &tree,
8199                                 &node))
8200     /* We aren't actually showing the node */
8201     goto done;
8202
8203   if (tree == NULL)
8204     goto done;
8205
8206   if (tree_view->priv->fixed_height_mode
8207       && tree_view->priv->fixed_height >= 0)
8208     {
8209       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8210       if (GTK_WIDGET_REALIZED (tree_view))
8211         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8212     }
8213   else
8214     {
8215       _gtk_rbtree_node_mark_invalid (tree, node);
8216       for (list = tree_view->priv->columns; list; list = list->next)
8217         {
8218           GtkTreeViewColumn *column;
8219
8220           column = list->data;
8221           if (! column->visible)
8222             continue;
8223
8224           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8225             {
8226               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8227             }
8228         }
8229     }
8230
8231  done:
8232   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8233     install_presize_handler (tree_view);
8234   if (free_path)
8235     gtk_tree_path_free (path);
8236 }
8237
8238 static void
8239 gtk_tree_view_row_inserted (GtkTreeModel *model,
8240                             GtkTreePath  *path,
8241                             GtkTreeIter  *iter,
8242                             gpointer      data)
8243 {
8244   GtkTreeView *tree_view = (GtkTreeView *) data;
8245   gint *indices;
8246   GtkRBTree *tmptree, *tree;
8247   GtkRBNode *tmpnode = NULL;
8248   gint depth;
8249   gint i = 0;
8250   gint height;
8251   gboolean free_path = FALSE;
8252   gboolean node_visible = TRUE;
8253
8254   g_return_if_fail (path != NULL || iter != NULL);
8255
8256   if (tree_view->priv->fixed_height_mode
8257       && tree_view->priv->fixed_height >= 0)
8258     height = tree_view->priv->fixed_height;
8259   else
8260     height = 0;
8261
8262   if (path == NULL)
8263     {
8264       path = gtk_tree_model_get_path (model, iter);
8265       free_path = TRUE;
8266     }
8267   else if (iter == NULL)
8268     gtk_tree_model_get_iter (model, iter, path);
8269
8270   if (tree_view->priv->tree == NULL)
8271     tree_view->priv->tree = _gtk_rbtree_new ();
8272
8273   tmptree = tree = tree_view->priv->tree;
8274
8275   /* Update all row-references */
8276   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8277   depth = gtk_tree_path_get_depth (path);
8278   indices = gtk_tree_path_get_indices (path);
8279
8280   /* First, find the parent tree */
8281   while (i < depth - 1)
8282     {
8283       if (tmptree == NULL)
8284         {
8285           /* We aren't showing the node */
8286           node_visible = FALSE;
8287           goto done;
8288         }
8289
8290       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8291       if (tmpnode == NULL)
8292         {
8293           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8294                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8295                      "before the parent was inserted.");
8296           goto done;
8297         }
8298       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8299         {
8300           /* FIXME enforce correct behavior on model, probably */
8301           /* In theory, the model should have emitted has_child_toggled here.  We
8302            * try to catch it anyway, just to be safe, in case the model hasn't.
8303            */
8304           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8305                                                            tree,
8306                                                            tmpnode);
8307           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8308           gtk_tree_path_free (tmppath);
8309           goto done;
8310         }
8311
8312       tmptree = tmpnode->children;
8313       tree = tmptree;
8314       i++;
8315     }
8316
8317   if (tree == NULL)
8318     {
8319       node_visible = FALSE;
8320       goto done;
8321     }
8322
8323   /* ref the node */
8324   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8325   if (indices[depth - 1] == 0)
8326     {
8327       tmpnode = _gtk_rbtree_find_count (tree, 1);
8328       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8329     }
8330   else
8331     {
8332       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8333       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8334     }
8335
8336  done:
8337   if (height > 0)
8338     {
8339       if (tree)
8340         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8341
8342       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8343         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8344       else
8345         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8346     }
8347   else
8348     install_presize_handler (tree_view);
8349   if (free_path)
8350     gtk_tree_path_free (path);
8351 }
8352
8353 static void
8354 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8355                                      GtkTreePath  *path,
8356                                      GtkTreeIter  *iter,
8357                                      gpointer      data)
8358 {
8359   GtkTreeView *tree_view = (GtkTreeView *)data;
8360   GtkTreeIter real_iter;
8361   gboolean has_child;
8362   GtkRBTree *tree;
8363   GtkRBNode *node;
8364   gboolean free_path = FALSE;
8365
8366   g_return_if_fail (path != NULL || iter != NULL);
8367
8368   if (iter)
8369     real_iter = *iter;
8370
8371   if (path == NULL)
8372     {
8373       path = gtk_tree_model_get_path (model, iter);
8374       free_path = TRUE;
8375     }
8376   else if (iter == NULL)
8377     gtk_tree_model_get_iter (model, &real_iter, path);
8378
8379   if (_gtk_tree_view_find_node (tree_view,
8380                                 path,
8381                                 &tree,
8382                                 &node))
8383     /* We aren't actually showing the node */
8384     goto done;
8385
8386   if (tree == NULL)
8387     goto done;
8388
8389   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8390   /* Sanity check.
8391    */
8392   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8393     goto done;
8394
8395   if (has_child)
8396     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8397   else
8398     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8399
8400   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8401     {
8402       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8403       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8404         {
8405           GList *list;
8406
8407           for (list = tree_view->priv->columns; list; list = list->next)
8408             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8409               {
8410                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8411                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8412                 break;
8413               }
8414         }
8415       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8416     }
8417   else
8418     {
8419       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8420     }
8421
8422  done:
8423   if (free_path)
8424     gtk_tree_path_free (path);
8425 }
8426
8427 static void
8428 count_children_helper (GtkRBTree *tree,
8429                        GtkRBNode *node,
8430                        gpointer   data)
8431 {
8432   if (node->children)
8433     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8434   (*((gint *)data))++;
8435 }
8436
8437 static void
8438 check_selection_helper (GtkRBTree *tree,
8439                         GtkRBNode *node,
8440                         gpointer   data)
8441 {
8442   gint *value = (gint *)data;
8443
8444   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8445
8446   if (node->children && !*value)
8447     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8448 }
8449
8450 static void
8451 gtk_tree_view_row_deleted (GtkTreeModel *model,
8452                            GtkTreePath  *path,
8453                            gpointer      data)
8454 {
8455   GtkTreeView *tree_view = (GtkTreeView *)data;
8456   GtkRBTree *tree;
8457   GtkRBNode *node;
8458   GList *list;
8459   gint selection_changed = FALSE;
8460
8461   g_return_if_fail (path != NULL);
8462
8463   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8464
8465   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8466     return;
8467
8468   if (tree == NULL)
8469     return;
8470
8471   /* check if the selection has been changed */
8472   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8473                         check_selection_helper, &selection_changed);
8474
8475   for (list = tree_view->priv->columns; list; list = list->next)
8476     if (((GtkTreeViewColumn *)list->data)->visible &&
8477         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8478       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8479
8480   /* Ensure we don't have a dangling pointer to a dead node */
8481   ensure_unprelighted (tree_view);
8482
8483   /* Cancel editting if we've started */
8484   gtk_tree_view_stop_editing (tree_view, TRUE);
8485
8486   /* If we have a node expanded/collapsed timeout, remove it */
8487   remove_expand_collapse_timeout (tree_view);
8488
8489   if (tree_view->priv->destroy_count_func)
8490     {
8491       gint child_count = 0;
8492       if (node->children)
8493         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8494       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8495     }
8496
8497   if (tree->root->count == 1)
8498     {
8499       if (tree_view->priv->tree == tree)
8500         tree_view->priv->tree = NULL;
8501
8502       _gtk_rbtree_remove (tree);
8503     }
8504   else
8505     {
8506       _gtk_rbtree_remove_node (tree, node);
8507     }
8508
8509   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8510     {
8511       gtk_tree_row_reference_free (tree_view->priv->top_row);
8512       tree_view->priv->top_row = NULL;
8513     }
8514
8515   install_scroll_sync_handler (tree_view);
8516
8517   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8518
8519   if (selection_changed)
8520     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8521 }
8522
8523 static void
8524 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8525                               GtkTreePath  *parent,
8526                               GtkTreeIter  *iter,
8527                               gint         *new_order,
8528                               gpointer      data)
8529 {
8530   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8531   GtkRBTree *tree;
8532   GtkRBNode *node;
8533   gint len;
8534
8535   len = gtk_tree_model_iter_n_children (model, iter);
8536
8537   if (len < 2)
8538     return;
8539
8540   gtk_tree_row_reference_reordered (G_OBJECT (data),
8541                                     parent,
8542                                     iter,
8543                                     new_order);
8544
8545   if (_gtk_tree_view_find_node (tree_view,
8546                                 parent,
8547                                 &tree,
8548                                 &node))
8549     return;
8550
8551   /* We need to special case the parent path */
8552   if (tree == NULL)
8553     tree = tree_view->priv->tree;
8554   else
8555     tree = node->children;
8556
8557   if (tree == NULL)
8558     return;
8559
8560   if (tree_view->priv->edited_column)
8561     gtk_tree_view_stop_editing (tree_view, TRUE);
8562
8563   /* we need to be unprelighted */
8564   ensure_unprelighted (tree_view);
8565
8566   /* clear the timeout */
8567   cancel_arrow_animation (tree_view);
8568   
8569   _gtk_rbtree_reorder (tree, new_order, len);
8570
8571   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8572
8573   gtk_tree_view_dy_to_top_row (tree_view);
8574 }
8575
8576
8577 /* Internal tree functions
8578  */
8579
8580
8581 static void
8582 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8583                                      GtkRBTree         *tree,
8584                                      GtkTreeViewColumn *column,
8585                                      gint              *x1,
8586                                      gint              *x2)
8587 {
8588   GtkTreeViewColumn *tmp_column = NULL;
8589   gint total_width;
8590   GList *list;
8591   gboolean rtl;
8592
8593   if (x1)
8594     *x1 = 0;
8595
8596   if (x2)
8597     *x2 = 0;
8598
8599   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8600
8601   total_width = 0;
8602   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8603        list;
8604        list = (rtl ? list->prev : list->next))
8605     {
8606       tmp_column = list->data;
8607
8608       if (tmp_column == column)
8609         break;
8610
8611       if (tmp_column->visible)
8612         total_width += tmp_column->width;
8613     }
8614
8615   if (tmp_column != column)
8616     {
8617       g_warning (G_STRLOC": passed-in column isn't in the tree");
8618       return;
8619     }
8620
8621   if (x1)
8622     *x1 = total_width;
8623
8624   if (x2)
8625     {
8626       if (column->visible)
8627         *x2 = total_width + column->width;
8628       else
8629         *x2 = total_width; /* width of 0 */
8630     }
8631 }
8632 static void
8633 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8634                                 GtkRBTree   *tree,
8635                                 gint        *x1,
8636                                 gint        *x2)
8637 {
8638   gint x_offset = 0;
8639   GList *list;
8640   GtkTreeViewColumn *tmp_column = NULL;
8641   gint total_width;
8642   gboolean indent_expanders;
8643   gboolean rtl;
8644
8645   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8646
8647   total_width = 0;
8648   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8649        list;
8650        list = (rtl ? list->prev : list->next))
8651     {
8652       tmp_column = list->data;
8653
8654       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8655         {
8656           if (rtl)
8657             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8658           else
8659             x_offset = total_width;
8660           break;
8661         }
8662
8663       if (tmp_column->visible)
8664         total_width += tmp_column->width;
8665     }
8666
8667   gtk_widget_style_get (GTK_WIDGET (tree_view),
8668                         "indent-expanders", &indent_expanders,
8669                         NULL);
8670
8671   if (indent_expanders)
8672     {
8673       if (rtl)
8674         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8675       else
8676         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8677     }
8678
8679   *x1 = x_offset;
8680   
8681   if (tmp_column && tmp_column->visible)
8682     /* +1 because x2 isn't included in the range. */
8683     *x2 = *x1 + tree_view->priv->expander_size + 1;
8684   else
8685     *x2 = *x1;
8686 }
8687
8688 static void
8689 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8690                           GtkRBTree   *tree,
8691                           GtkTreeIter *iter,
8692                           gint         depth,
8693                           gboolean     recurse)
8694 {
8695   GtkRBNode *temp = NULL;
8696   GtkTreePath *path = NULL;
8697   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8698
8699   do
8700     {
8701       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8702       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8703
8704       if (tree_view->priv->fixed_height > 0)
8705         {
8706           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8707             {
8708               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8709               _gtk_rbtree_node_mark_valid (tree, temp);
8710             }
8711         }
8712
8713       if (is_list)
8714         continue;
8715
8716       if (recurse)
8717         {
8718           GtkTreeIter child;
8719
8720           if (!path)
8721             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8722           else
8723             gtk_tree_path_next (path);
8724
8725           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8726             {
8727               gboolean expand;
8728
8729               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8730
8731               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8732                   && !expand)
8733                 {
8734                   temp->children = _gtk_rbtree_new ();
8735                   temp->children->parent_tree = tree;
8736                   temp->children->parent_node = temp;
8737                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8738                 }
8739             }
8740         }
8741
8742       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8743         {
8744           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8745             temp->flags ^= GTK_RBNODE_IS_PARENT;
8746         }
8747     }
8748   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8749
8750   if (path)
8751     gtk_tree_path_free (path);
8752 }
8753
8754 /* If height is non-NULL, then we set it to be the new height.  if it's all
8755  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
8756  */
8757 static gboolean
8758 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
8759                                    GtkTreeIter *iter,
8760                                    gint         depth,
8761                                    gint        *height,
8762                                    GtkRBNode   *node)
8763 {
8764   GtkTreeViewColumn *column;
8765   GList *list;
8766   gboolean retval = FALSE;
8767   gint tmpheight;
8768   gint horizontal_separator;
8769
8770   gtk_widget_style_get (GTK_WIDGET (tree_view),
8771                         "horizontal-separator", &horizontal_separator,
8772                         NULL);
8773
8774   if (height)
8775     *height = -1;
8776
8777   for (list = tree_view->priv->columns; list; list = list->next)
8778     {
8779       gint width;
8780       column = list->data;
8781       if (column->dirty == TRUE)
8782         continue;
8783       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
8784         continue;
8785       if (!column->visible)
8786         continue;
8787
8788       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
8789                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
8790                                                node->children?TRUE:FALSE);
8791
8792       if (height)
8793         {
8794           gtk_tree_view_column_cell_get_size (column,
8795                                               NULL, NULL, NULL,
8796                                               &width, &tmpheight);
8797           *height = MAX (*height, tmpheight);
8798         }
8799       else
8800         {
8801           gtk_tree_view_column_cell_get_size (column,
8802                                               NULL, NULL, NULL,
8803                                               &width, NULL);
8804         }
8805
8806       if (gtk_tree_view_is_expander_column (tree_view, column))
8807         {
8808           int tmp = 0;
8809
8810           tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
8811           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
8812             tmp += depth * tree_view->priv->expander_size;
8813
8814           if (tmp > column->requested_width)
8815             {
8816               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8817               retval = TRUE;
8818             }
8819         }
8820       else
8821         {
8822           if (horizontal_separator + width > column->requested_width)
8823             {
8824               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8825               retval = TRUE;
8826             }
8827         }
8828     }
8829
8830   return retval;
8831 }
8832
8833 static void
8834 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
8835                               GtkRBTree   *tree,
8836                               GtkTreeIter *iter,
8837                               gint         depth)
8838 {
8839   GtkRBNode *temp = tree->root;
8840   GtkTreeViewColumn *column;
8841   GList *list;
8842   GtkTreeIter child;
8843   gboolean is_all_dirty;
8844
8845   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
8846
8847   while (temp->left != tree->nil)
8848     temp = temp->left;
8849
8850   do
8851     {
8852       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
8853       is_all_dirty = TRUE;
8854       for (list = tree_view->priv->columns; list; list = list->next)
8855         {
8856           column = list->data;
8857           if (column->dirty == FALSE)
8858             {
8859               is_all_dirty = FALSE;
8860               break;
8861             }
8862         }
8863
8864       if (is_all_dirty)
8865         return;
8866
8867       gtk_tree_view_discover_dirty_iter (tree_view,
8868                                          iter,
8869                                          depth,
8870                                          NULL,
8871                                          temp);
8872       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
8873           temp->children != NULL)
8874         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
8875       temp = _gtk_rbtree_next (tree, temp);
8876     }
8877   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8878 }
8879
8880
8881 /* Make sure the node is visible vertically */
8882 static void
8883 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8884                                   GtkRBTree   *tree,
8885                                   GtkRBNode   *node)
8886 {
8887   gint node_dy, height;
8888   GtkTreePath *path = NULL;
8889
8890   if (!GTK_WIDGET_REALIZED (tree_view))
8891     return;
8892
8893   /* just return if the node is visible, avoiding a costly expose */
8894   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8895   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8896   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8897       && node_dy >= tree_view->priv->vadjustment->value
8898       && node_dy + height <= (tree_view->priv->vadjustment->value
8899                               + tree_view->priv->vadjustment->page_size))
8900     return;
8901
8902   path = _gtk_tree_view_find_path (tree_view, tree, node);
8903   if (path)
8904     {
8905       /* We process updates because we want to clear old selected items when we scroll.
8906        * if this is removed, we get a "selection streak" at the bottom. */
8907       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8908       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8909       gtk_tree_path_free (path);
8910     }
8911 }
8912
8913 static void
8914 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8915                                     GtkTreeViewColumn *column,
8916                                     gboolean           focus_to_cell)
8917 {
8918   gint x, width;
8919
8920   if (column == NULL)
8921     return;
8922
8923   x = column->button->allocation.x;
8924   width = column->button->allocation.width;
8925
8926   if (width > tree_view->priv->hadjustment->page_size)
8927     {
8928       /* The column is larger than the horizontal page size.  If the
8929        * column has cells which can be focussed individually, then we make
8930        * sure the cell which gets focus is fully visible (if even the
8931        * focus cell is bigger than the page size, we make sure the
8932        * left-hand side of the cell is visible).
8933        *
8934        * If the column does not have those so-called special cells, we
8935        * make sure the left-hand side of the column is visible.
8936        */
8937
8938       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8939         {
8940           GtkTreePath *cursor_path;
8941           GdkRectangle background_area, cell_area, focus_area;
8942
8943           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8944
8945           gtk_tree_view_get_cell_area (tree_view,
8946                                        cursor_path, column, &cell_area);
8947           gtk_tree_view_get_background_area (tree_view,
8948                                              cursor_path, column,
8949                                              &background_area);
8950
8951           gtk_tree_path_free (cursor_path);
8952
8953           _gtk_tree_view_column_get_focus_area (column,
8954                                                 &background_area,
8955                                                 &cell_area,
8956                                                 &focus_area);
8957
8958           x = focus_area.x;
8959           width = focus_area.width;
8960
8961           if (width < tree_view->priv->hadjustment->page_size)
8962             {
8963               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8964                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8965                                           x + width - tree_view->priv->hadjustment->page_size);
8966               else if (tree_view->priv->hadjustment->value > x)
8967                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8968             }
8969         }
8970
8971       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8972                                 CLAMP (x,
8973                                        tree_view->priv->hadjustment->lower,
8974                                        tree_view->priv->hadjustment->upper
8975                                        - tree_view->priv->hadjustment->page_size));
8976     }
8977   else
8978     {
8979       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8980           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8981                                     x + width - tree_view->priv->hadjustment->page_size);
8982       else if (tree_view->priv->hadjustment->value > x)
8983         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8984   }
8985 }
8986
8987 /* This function could be more efficient.  I'll optimize it if profiling seems
8988  * to imply that it is important */
8989 GtkTreePath *
8990 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8991                           GtkRBTree   *tree,
8992                           GtkRBNode   *node)
8993 {
8994   GtkTreePath *path;
8995   GtkRBTree *tmp_tree;
8996   GtkRBNode *tmp_node, *last;
8997   gint count;
8998
8999   path = gtk_tree_path_new ();
9000
9001   g_return_val_if_fail (node != NULL, path);
9002   g_return_val_if_fail (node != tree->nil, path);
9003
9004   count = 1 + node->left->count;
9005
9006   last = node;
9007   tmp_node = node->parent;
9008   tmp_tree = tree;
9009   while (tmp_tree)
9010     {
9011       while (tmp_node != tmp_tree->nil)
9012         {
9013           if (tmp_node->right == last)
9014             count += 1 + tmp_node->left->count;
9015           last = tmp_node;
9016           tmp_node = tmp_node->parent;
9017         }
9018       gtk_tree_path_prepend_index (path, count - 1);
9019       last = tmp_tree->parent_node;
9020       tmp_tree = tmp_tree->parent_tree;
9021       if (last)
9022         {
9023           count = 1 + last->left->count;
9024           tmp_node = last->parent;
9025         }
9026     }
9027   return path;
9028 }
9029
9030 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9031  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9032  * both set to NULL.
9033  */
9034 gboolean
9035 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9036                           GtkTreePath  *path,
9037                           GtkRBTree   **tree,
9038                           GtkRBNode   **node)
9039 {
9040   GtkRBNode *tmpnode = NULL;
9041   GtkRBTree *tmptree = tree_view->priv->tree;
9042   gint *indices = gtk_tree_path_get_indices (path);
9043   gint depth = gtk_tree_path_get_depth (path);
9044   gint i = 0;
9045
9046   *node = NULL;
9047   *tree = NULL;
9048
9049   if (depth == 0 || tmptree == NULL)
9050     return FALSE;
9051   do
9052     {
9053       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9054       ++i;
9055       if (tmpnode == NULL)
9056         {
9057           *tree = NULL;
9058           *node = NULL;
9059           return FALSE;
9060         }
9061       if (i >= depth)
9062         {
9063           *tree = tmptree;
9064           *node = tmpnode;
9065           return FALSE;
9066         }
9067       *tree = tmptree;
9068       *node = tmpnode;
9069       tmptree = tmpnode->children;
9070       if (tmptree == NULL)
9071         return TRUE;
9072     }
9073   while (1);
9074 }
9075
9076 static gboolean
9077 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9078                                   GtkTreeViewColumn *column)
9079 {
9080   GList *list;
9081
9082   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9083     return FALSE;
9084
9085   if (tree_view->priv->expander_column != NULL)
9086     {
9087       if (tree_view->priv->expander_column == column)
9088         return TRUE;
9089       return FALSE;
9090     }
9091   else
9092     {
9093       for (list = tree_view->priv->columns;
9094            list;
9095            list = list->next)
9096         if (((GtkTreeViewColumn *)list->data)->visible)
9097           break;
9098       if (list && list->data == column)
9099         return TRUE;
9100     }
9101   return FALSE;
9102 }
9103
9104 static void
9105 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9106                                 guint           keyval,
9107                                 guint           modmask,
9108                                 gboolean        add_shifted_binding,
9109                                 GtkMovementStep step,
9110                                 gint            count)
9111 {
9112   
9113   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9114                                 "move-cursor", 2,
9115                                 G_TYPE_ENUM, step,
9116                                 G_TYPE_INT, count);
9117
9118   if (add_shifted_binding)
9119     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9120                                   "move-cursor", 2,
9121                                   G_TYPE_ENUM, step,
9122                                   G_TYPE_INT, count);
9123
9124   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9125    return;
9126
9127   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9128                                 "move-cursor", 2,
9129                                 G_TYPE_ENUM, step,
9130                                 G_TYPE_INT, count);
9131
9132   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9133                                 "move-cursor", 2,
9134                                 G_TYPE_ENUM, step,
9135                                 G_TYPE_INT, count);
9136 }
9137
9138 static gint
9139 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9140                                  GtkTreeIter  *iter,
9141                                  GtkRBTree    *tree,
9142                                  GtkRBNode    *node)
9143 {
9144   gint retval = FALSE;
9145   do
9146     {
9147       g_return_val_if_fail (node != NULL, FALSE);
9148
9149       if (node->children)
9150         {
9151           GtkTreeIter child;
9152           GtkRBTree *new_tree;
9153           GtkRBNode *new_node;
9154
9155           new_tree = node->children;
9156           new_node = new_tree->root;
9157
9158           while (new_node && new_node->left != new_tree->nil)
9159             new_node = new_node->left;
9160
9161           if (!gtk_tree_model_iter_children (model, &child, iter))
9162             return FALSE;
9163
9164           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9165         }
9166
9167       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9168         retval = TRUE;
9169       gtk_tree_model_unref_node (model, iter);
9170       node = _gtk_rbtree_next (tree, node);
9171     }
9172   while (gtk_tree_model_iter_next (model, iter));
9173
9174   return retval;
9175 }
9176
9177 static gint
9178 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9179                                               GtkRBTree   *tree)
9180 {
9181   GtkTreeIter iter;
9182   GtkTreePath *path;
9183   GtkRBNode *node;
9184   gint retval;
9185
9186   if (!tree)
9187     return FALSE;
9188
9189   node = tree->root;
9190   while (node && node->left != tree->nil)
9191     node = node->left;
9192
9193   g_return_val_if_fail (node != NULL, FALSE);
9194   path = _gtk_tree_view_find_path (tree_view, tree, node);
9195   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9196                            &iter, path);
9197   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9198   gtk_tree_path_free (path);
9199
9200   return retval;
9201 }
9202
9203 static void
9204 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9205                                     GtkTreeViewColumn *column)
9206 {
9207   GtkTreeViewColumn *left_column;
9208   GtkTreeViewColumn *cur_column = NULL;
9209   GtkTreeViewColumnReorder *reorder;
9210   gboolean rtl;
9211   GList *tmp_list;
9212   gint left;
9213
9214   /* We want to precalculate the motion list such that we know what column slots
9215    * are available.
9216    */
9217   left_column = NULL;
9218   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9219
9220   /* First, identify all possible drop spots */
9221   if (rtl)
9222     tmp_list = g_list_last (tree_view->priv->columns);
9223   else
9224     tmp_list = g_list_first (tree_view->priv->columns);
9225
9226   while (tmp_list)
9227     {
9228       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9229       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9230
9231       if (cur_column->visible == FALSE)
9232         continue;
9233
9234       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9235       if (left_column != column && cur_column != column &&
9236           tree_view->priv->column_drop_func &&
9237           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9238         {
9239           left_column = cur_column;
9240           continue;
9241         }
9242       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9243       reorder->left_column = left_column;
9244       left_column = reorder->right_column = cur_column;
9245
9246       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9247     }
9248
9249   /* Add the last one */
9250   if (tree_view->priv->column_drop_func == NULL ||
9251       ((left_column != column) &&
9252        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9253     {
9254       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9255       reorder->left_column = left_column;
9256       reorder->right_column = NULL;
9257       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9258     }
9259
9260   /* We quickly check to see if it even makes sense to reorder columns. */
9261   /* If there is nothing that can be moved, then we return */
9262
9263   if (tree_view->priv->column_drag_info == NULL)
9264     return;
9265
9266   /* We know there are always 2 slots possbile, as you can always return column. */
9267   /* If that's all there is, return */
9268   if (tree_view->priv->column_drag_info->next == NULL || 
9269       (tree_view->priv->column_drag_info->next->next == NULL &&
9270        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9271        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9272     {
9273       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9274         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9275       g_list_free (tree_view->priv->column_drag_info);
9276       tree_view->priv->column_drag_info = NULL;
9277       return;
9278     }
9279   /* We fill in the ranges for the columns, now that we've isolated them */
9280   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9281
9282   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9283     {
9284       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9285
9286       reorder->left_align = left;
9287       if (tmp_list->next != NULL)
9288         {
9289           g_assert (tmp_list->next->data);
9290           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9291                                          reorder->right_column->button->allocation.width +
9292                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9293         }
9294       else
9295         {
9296           gint width;
9297
9298           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9299           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9300         }
9301     }
9302 }
9303
9304 void
9305 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9306                                   GtkTreeViewColumn *column)
9307 {
9308   GdkEvent *send_event;
9309   GtkAllocation allocation;
9310   gint x, y, width, height;
9311   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9312   GdkDisplay *display = gdk_screen_get_display (screen);
9313
9314   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9315   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9316
9317   gtk_tree_view_set_column_drag_info (tree_view, column);
9318
9319   if (tree_view->priv->column_drag_info == NULL)
9320     return;
9321
9322   if (tree_view->priv->drag_window == NULL)
9323     {
9324       GdkWindowAttr attributes;
9325       guint attributes_mask;
9326
9327       attributes.window_type = GDK_WINDOW_CHILD;
9328       attributes.wclass = GDK_INPUT_OUTPUT;
9329       attributes.x = column->button->allocation.x;
9330       attributes.y = 0;
9331       attributes.width = column->button->allocation.width;
9332       attributes.height = column->button->allocation.height;
9333       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9334       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9335       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9336       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9337
9338       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9339                                                      &attributes,
9340                                                      attributes_mask);
9341       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9342     }
9343
9344   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9345   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9346
9347   gtk_grab_remove (column->button);
9348
9349   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9350   send_event->crossing.send_event = TRUE;
9351   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9352   send_event->crossing.subwindow = NULL;
9353   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9354   send_event->crossing.time = GDK_CURRENT_TIME;
9355
9356   gtk_propagate_event (column->button, send_event);
9357   gdk_event_free (send_event);
9358
9359   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9360   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9361   send_event->button.send_event = TRUE;
9362   send_event->button.time = GDK_CURRENT_TIME;
9363   send_event->button.x = -1;
9364   send_event->button.y = -1;
9365   send_event->button.axes = NULL;
9366   send_event->button.state = 0;
9367   send_event->button.button = 1;
9368   send_event->button.device = gdk_display_get_core_pointer (display);
9369   send_event->button.x_root = 0;
9370   send_event->button.y_root = 0;
9371
9372   gtk_propagate_event (column->button, send_event);
9373   gdk_event_free (send_event);
9374
9375   /* Kids, don't try this at home */
9376   g_object_ref (column->button);
9377   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9378   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9379   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9380   g_object_unref (column->button);
9381
9382   tree_view->priv->drag_column_x = column->button->allocation.x;
9383   allocation = column->button->allocation;
9384   allocation.x = 0;
9385   gtk_widget_size_allocate (column->button, &allocation);
9386   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9387
9388   tree_view->priv->drag_column = column;
9389   gdk_window_show (tree_view->priv->drag_window);
9390
9391   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9392   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9393
9394   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9395   while (gtk_events_pending ())
9396     gtk_main_iteration ();
9397
9398   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9399   gdk_pointer_grab (tree_view->priv->drag_window,
9400                     FALSE,
9401                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9402                     NULL, NULL, GDK_CURRENT_TIME);
9403   gdk_keyboard_grab (tree_view->priv->drag_window,
9404                      FALSE,
9405                      GDK_CURRENT_TIME);
9406 }
9407
9408 static void
9409 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9410                                 GtkRBTree          *tree,
9411                                 GtkRBNode          *node,
9412                                 const GdkRectangle *clip_rect)
9413 {
9414   GdkRectangle rect;
9415
9416   if (!GTK_WIDGET_REALIZED (tree_view))
9417     return;
9418
9419   rect.x = 0;
9420   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9421
9422   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9423   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9424
9425   if (clip_rect)
9426     {
9427       GdkRectangle new_rect;
9428
9429       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9430
9431       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9432     }
9433   else
9434     {
9435       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9436     }
9437 }
9438
9439 void
9440 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9441                                 GtkRBTree          *tree,
9442                                 GtkRBNode          *node,
9443                                 const GdkRectangle *clip_rect)
9444 {
9445   GdkRectangle rect;
9446
9447   if (!GTK_WIDGET_REALIZED (tree_view))
9448     return;
9449
9450   rect.x = 0;
9451   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9452
9453   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9454   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9455
9456   if (clip_rect)
9457     {
9458       GdkRectangle new_rect;
9459
9460       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9461
9462       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9463     }
9464   else
9465     {
9466       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9467     }
9468 }
9469
9470 static void
9471 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9472                                GtkTreePath        *path,
9473                                const GdkRectangle *clip_rect)
9474 {
9475   GtkRBTree *tree = NULL;
9476   GtkRBNode *node = NULL;
9477
9478   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9479
9480   if (tree)
9481     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9482 }
9483
9484 /* x and y are the mouse position
9485  */
9486 static void
9487 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9488                           GtkRBTree   *tree,
9489                           GtkRBNode   *node,
9490                           /* in bin_window coordinates */
9491                           gint         x,
9492                           gint         y)
9493 {
9494   GdkRectangle area;
9495   GtkStateType state;
9496   GtkWidget *widget;
9497   gint x_offset = 0;
9498   gint x2;
9499   gint vertical_separator;
9500   gint expander_size;
9501   GtkExpanderStyle expander_style;
9502
9503   gtk_widget_style_get (GTK_WIDGET (tree_view),
9504                         "vertical-separator", &vertical_separator,
9505                         NULL);
9506   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9507
9508   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9509     return;
9510
9511   widget = GTK_WIDGET (tree_view);
9512
9513   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9514
9515   area.x = x_offset;
9516   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9517   area.width = expander_size + 2;
9518   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9519
9520   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9521     {
9522       state = GTK_STATE_INSENSITIVE;
9523     }
9524   else if (node == tree_view->priv->button_pressed_node)
9525     {
9526       if (x >= area.x && x <= (area.x + area.width) &&
9527           y >= area.y && y <= (area.y + area.height))
9528         state = GTK_STATE_ACTIVE;
9529       else
9530         state = GTK_STATE_NORMAL;
9531     }
9532   else
9533     {
9534       if (node == tree_view->priv->prelight_node &&
9535           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9536         state = GTK_STATE_PRELIGHT;
9537       else
9538         state = GTK_STATE_NORMAL;
9539     }
9540
9541   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9542     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9543   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9544     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9545   else if (node->children != NULL)
9546     expander_style = GTK_EXPANDER_EXPANDED;
9547   else
9548     expander_style = GTK_EXPANDER_COLLAPSED;
9549
9550   gtk_paint_expander (widget->style,
9551                       tree_view->priv->bin_window,
9552                       state,
9553                       &area,
9554                       widget,
9555                       "treeview",
9556                       area.x + area.width / 2,
9557                       area.y + area.height / 2,
9558                       expander_style);
9559 }
9560
9561 static void
9562 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9563
9564 {
9565   GtkTreePath *cursor_path;
9566
9567   if ((tree_view->priv->tree == NULL) ||
9568       (! GTK_WIDGET_REALIZED (tree_view)))
9569     return;
9570
9571   cursor_path = NULL;
9572   if (tree_view->priv->cursor)
9573     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9574
9575   if (cursor_path == NULL)
9576     {
9577       /* Consult the selection before defaulting to the
9578        * first focusable element
9579        */
9580       GList *selected_rows;
9581       GtkTreeModel *model;
9582       GtkTreeSelection *selection;
9583
9584       selection = gtk_tree_view_get_selection (tree_view);
9585       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9586
9587       if (selected_rows)
9588         {
9589           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9590           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9591           g_list_free (selected_rows);
9592         }
9593       else
9594         {
9595           cursor_path = gtk_tree_path_new_first ();
9596           search_first_focusable_path (tree_view, &cursor_path,
9597                                        TRUE, NULL, NULL);
9598         }
9599
9600       gtk_tree_row_reference_free (tree_view->priv->cursor);
9601       tree_view->priv->cursor = NULL;
9602
9603       if (cursor_path)
9604         {
9605           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9606             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9607           else
9608             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9609         }
9610     }
9611
9612   if (cursor_path)
9613     {
9614       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9615
9616       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9617       gtk_tree_path_free (cursor_path);
9618
9619       if (tree_view->priv->focus_column == NULL)
9620         {
9621           GList *list;
9622           for (list = tree_view->priv->columns; list; list = list->next)
9623             {
9624               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9625                 {
9626                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9627                   break;
9628                 }
9629             }
9630         }
9631     }
9632 }
9633
9634 static void
9635 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9636                                    gint         count)
9637 {
9638   gint selection_count;
9639   GtkRBTree *cursor_tree = NULL;
9640   GtkRBNode *cursor_node = NULL;
9641   GtkRBTree *new_cursor_tree = NULL;
9642   GtkRBNode *new_cursor_node = NULL;
9643   GtkTreePath *cursor_path = NULL;
9644   gboolean grab_focus = TRUE;
9645   gboolean selectable;
9646
9647   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9648     return;
9649
9650   cursor_path = NULL;
9651   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9652     /* FIXME: we lost the cursor; should we get the first? */
9653     return;
9654
9655   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9656   _gtk_tree_view_find_node (tree_view, cursor_path,
9657                             &cursor_tree, &cursor_node);
9658
9659   if (cursor_tree == NULL)
9660     /* FIXME: we lost the cursor; should we get the first? */
9661     return;
9662
9663   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9664   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9665                                                       cursor_node,
9666                                                       cursor_path);
9667
9668   if (selection_count == 0
9669       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9670       && !tree_view->priv->ctrl_pressed
9671       && selectable)
9672     {
9673       /* Don't move the cursor, but just select the current node */
9674       new_cursor_tree = cursor_tree;
9675       new_cursor_node = cursor_node;
9676     }
9677   else
9678     {
9679       if (count == -1)
9680         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9681                                &new_cursor_tree, &new_cursor_node);
9682       else
9683         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9684                                &new_cursor_tree, &new_cursor_node);
9685     }
9686
9687   gtk_tree_path_free (cursor_path);
9688
9689   if (new_cursor_node)
9690     {
9691       cursor_path = _gtk_tree_view_find_path (tree_view,
9692                                               new_cursor_tree, new_cursor_node);
9693
9694       search_first_focusable_path (tree_view, &cursor_path,
9695                                    (count != -1),
9696                                    &new_cursor_tree,
9697                                    &new_cursor_node);
9698
9699       if (cursor_path)
9700         gtk_tree_path_free (cursor_path);
9701     }
9702
9703   /*
9704    * If the list has only one item and multi-selection is set then select
9705    * the row (if not yet selected).
9706    */
9707   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9708       new_cursor_node == NULL)
9709     {
9710       if (count == -1)
9711         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9712                                &new_cursor_tree, &new_cursor_node);
9713       else
9714         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9715                                &new_cursor_tree, &new_cursor_node);
9716
9717       if (new_cursor_node == NULL
9718           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9719         {
9720           new_cursor_node = cursor_node;
9721           new_cursor_tree = cursor_tree;
9722         }
9723       else
9724         {
9725           new_cursor_node = NULL;
9726         }
9727     }
9728
9729   if (new_cursor_node)
9730     {
9731       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9732       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9733       gtk_tree_path_free (cursor_path);
9734     }
9735   else
9736     {
9737       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9738
9739       if (!tree_view->priv->shift_pressed)
9740         {
9741           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9742                                           count < 0 ?
9743                                           GTK_DIR_UP : GTK_DIR_DOWN))
9744             {
9745               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9746
9747               if (toplevel)
9748                 gtk_widget_child_focus (toplevel,
9749                                         count < 0 ?
9750                                         GTK_DIR_TAB_BACKWARD :
9751                                         GTK_DIR_TAB_FORWARD);
9752
9753               grab_focus = FALSE;
9754             }
9755         }
9756       else
9757         {
9758           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9759         }
9760     }
9761
9762   if (grab_focus)
9763     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9764 }
9765
9766 static void
9767 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9768                                         gint         count)
9769 {
9770   GtkRBTree *cursor_tree = NULL;
9771   GtkRBNode *cursor_node = NULL;
9772   GtkTreePath *old_cursor_path = NULL;
9773   GtkTreePath *cursor_path = NULL;
9774   GtkRBTree *start_cursor_tree = NULL;
9775   GtkRBNode *start_cursor_node = NULL;
9776   gint y;
9777   gint window_y;
9778   gint vertical_separator;
9779
9780   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9781     return;
9782
9783   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9784     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9785   else
9786     /* This is sorta weird.  Focus in should give us a cursor */
9787     return;
9788
9789   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9790   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9791                             &cursor_tree, &cursor_node);
9792
9793   if (cursor_tree == NULL)
9794     {
9795       /* FIXME: we lost the cursor.  Should we try to get one? */
9796       gtk_tree_path_free (old_cursor_path);
9797       return;
9798     }
9799   g_return_if_fail (cursor_node != NULL);
9800
9801   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9802   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9803   y += tree_view->priv->cursor_offset;
9804   y += count * (int)tree_view->priv->vadjustment->page_increment;
9805   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9806
9807   if (y >= tree_view->priv->height)
9808     y = tree_view->priv->height - 1;
9809
9810   tree_view->priv->cursor_offset =
9811     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9812                              &cursor_tree, &cursor_node);
9813
9814   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9815     {
9816       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9817                              &cursor_tree, &cursor_node);
9818       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9819     }
9820
9821   y -= tree_view->priv->cursor_offset;
9822   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9823
9824   start_cursor_tree = cursor_tree;
9825   start_cursor_node = cursor_node;
9826
9827   if (! search_first_focusable_path (tree_view, &cursor_path,
9828                                      (count != -1),
9829                                      &cursor_tree, &cursor_node))
9830     {
9831       /* It looks like we reached the end of the view without finding
9832        * a focusable row.  We will step backwards to find the last
9833        * focusable row.
9834        */
9835       cursor_tree = start_cursor_tree;
9836       cursor_node = start_cursor_node;
9837       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9838
9839       search_first_focusable_path (tree_view, &cursor_path,
9840                                    (count == -1),
9841                                    &cursor_tree, &cursor_node);
9842     }
9843
9844   if (!cursor_path)
9845     goto cleanup;
9846
9847   /* update y */
9848   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9849
9850   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9851
9852   y -= window_y;
9853   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9854   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9855   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9856
9857   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9858     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9859
9860 cleanup:
9861   gtk_tree_path_free (old_cursor_path);
9862   gtk_tree_path_free (cursor_path);
9863 }
9864
9865 static void
9866 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9867                                       gint         count)
9868 {
9869   GtkRBTree *cursor_tree = NULL;
9870   GtkRBNode *cursor_node = NULL;
9871   GtkTreePath *cursor_path = NULL;
9872   GtkTreeViewColumn *column;
9873   GtkTreeIter iter;
9874   GList *list;
9875   gboolean found_column = FALSE;
9876   gboolean rtl;
9877
9878   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9879
9880   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9881     return;
9882
9883   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9884     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9885   else
9886     return;
9887
9888   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9889   if (cursor_tree == NULL)
9890     return;
9891   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9892     {
9893       gtk_tree_path_free (cursor_path);
9894       return;
9895     }
9896   gtk_tree_path_free (cursor_path);
9897
9898   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9899   if (tree_view->priv->focus_column)
9900     {
9901       for (; list; list = (rtl ? list->prev : list->next))
9902         {
9903           if (list->data == tree_view->priv->focus_column)
9904             break;
9905         }
9906     }
9907
9908   while (list)
9909     {
9910       gboolean left, right;
9911
9912       column = list->data;
9913       if (column->visible == FALSE)
9914         goto loop_end;
9915
9916       gtk_tree_view_column_cell_set_cell_data (column,
9917                                                tree_view->priv->model,
9918                                                &iter,
9919                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9920                                                cursor_node->children?TRUE:FALSE);
9921
9922       if (rtl)
9923         {
9924           right = list->prev ? TRUE : FALSE;
9925           left = list->next ? TRUE : FALSE;
9926         }
9927       else
9928         {
9929           left = list->prev ? TRUE : FALSE;
9930           right = list->next ? TRUE : FALSE;
9931         }
9932
9933       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9934         {
9935           tree_view->priv->focus_column = column;
9936           found_column = TRUE;
9937           break;
9938         }
9939     loop_end:
9940       if (count == 1)
9941         list = rtl ? list->prev : list->next;
9942       else
9943         list = rtl ? list->next : list->prev;
9944     }
9945
9946   if (found_column)
9947     {
9948       if (!gtk_tree_view_has_special_cell (tree_view))
9949         _gtk_tree_view_queue_draw_node (tree_view,
9950                                         cursor_tree,
9951                                         cursor_node,
9952                                         NULL);
9953       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9954     }
9955   else
9956     {
9957       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9958     }
9959
9960   gtk_tree_view_clamp_column_visible (tree_view,
9961                                       tree_view->priv->focus_column, TRUE);
9962 }
9963
9964 static void
9965 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9966                                      gint         count)
9967 {
9968   GtkRBTree *cursor_tree;
9969   GtkRBNode *cursor_node;
9970   GtkTreePath *path;
9971   GtkTreePath *old_path;
9972
9973   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9974     return;
9975
9976   g_return_if_fail (tree_view->priv->tree != NULL);
9977
9978   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9979
9980   cursor_tree = tree_view->priv->tree;
9981   cursor_node = cursor_tree->root;
9982
9983   if (count == -1)
9984     {
9985       while (cursor_node && cursor_node->left != cursor_tree->nil)
9986         cursor_node = cursor_node->left;
9987
9988       /* Now go forward to find the first focusable row. */
9989       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9990       search_first_focusable_path (tree_view, &path,
9991                                    TRUE, &cursor_tree, &cursor_node);
9992     }
9993   else
9994     {
9995       do
9996         {
9997           while (cursor_node && cursor_node->right != cursor_tree->nil)
9998             cursor_node = cursor_node->right;
9999           if (cursor_node->children == NULL)
10000             break;
10001
10002           cursor_tree = cursor_node->children;
10003           cursor_node = cursor_tree->root;
10004         }
10005       while (1);
10006
10007       /* Now go backwards to find last focusable row. */
10008       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10009       search_first_focusable_path (tree_view, &path,
10010                                    FALSE, &cursor_tree, &cursor_node);
10011     }
10012
10013   if (!path)
10014     goto cleanup;
10015
10016   if (gtk_tree_path_compare (old_path, path))
10017     {
10018       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10019     }
10020   else
10021     {
10022       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10023     }
10024
10025 cleanup:
10026   gtk_tree_path_free (old_path);
10027   gtk_tree_path_free (path);
10028 }
10029
10030 static gboolean
10031 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10032 {
10033   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10034     return FALSE;
10035
10036   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10037     return FALSE;
10038
10039   gtk_tree_selection_select_all (tree_view->priv->selection);
10040
10041   return TRUE;
10042 }
10043
10044 static gboolean
10045 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10046 {
10047   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10048     return FALSE;
10049
10050   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10051     return FALSE;
10052
10053   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10054
10055   return TRUE;
10056 }
10057
10058 static gboolean
10059 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10060                                       gboolean     start_editing)
10061 {
10062   GtkRBTree *new_tree = NULL;
10063   GtkRBNode *new_node = NULL;
10064   GtkRBTree *cursor_tree = NULL;
10065   GtkRBNode *cursor_node = NULL;
10066   GtkTreePath *cursor_path = NULL;
10067   GtkTreeSelectMode mode = 0;
10068
10069   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10070     return FALSE;
10071
10072   if (tree_view->priv->cursor)
10073     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10074
10075   if (cursor_path == NULL)
10076     return FALSE;
10077
10078   _gtk_tree_view_find_node (tree_view, cursor_path,
10079                             &cursor_tree, &cursor_node);
10080
10081   if (cursor_tree == NULL)
10082     {
10083       gtk_tree_path_free (cursor_path);
10084       return FALSE;
10085     }
10086
10087   if (!tree_view->priv->shift_pressed && start_editing &&
10088       tree_view->priv->focus_column)
10089     {
10090       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10091         {
10092           gtk_tree_path_free (cursor_path);
10093           return TRUE;
10094         }
10095     }
10096
10097   if (tree_view->priv->ctrl_pressed)
10098     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10099   if (tree_view->priv->shift_pressed)
10100     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10101
10102   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10103                                             cursor_node,
10104                                             cursor_tree,
10105                                             cursor_path,
10106                                             mode,
10107                                             FALSE);
10108
10109   /* We bail out if the original (tree, node) don't exist anymore after
10110    * handling the selection-changed callback.  We do return TRUE because
10111    * the key press has been handled at this point.
10112    */
10113   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10114
10115   if (cursor_tree != new_tree || cursor_node != new_node)
10116     return FALSE;
10117
10118   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10119
10120   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10121   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10122
10123   if (!tree_view->priv->shift_pressed)
10124     gtk_tree_view_row_activated (tree_view, cursor_path,
10125                                  tree_view->priv->focus_column);
10126     
10127   gtk_tree_path_free (cursor_path);
10128
10129   return TRUE;
10130 }
10131
10132 static gboolean
10133 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10134 {
10135   GtkRBTree *new_tree = NULL;
10136   GtkRBNode *new_node = NULL;
10137   GtkRBTree *cursor_tree = NULL;
10138   GtkRBNode *cursor_node = NULL;
10139   GtkTreePath *cursor_path = NULL;
10140
10141   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10142     return FALSE;
10143
10144   cursor_path = NULL;
10145   if (tree_view->priv->cursor)
10146     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10147
10148   if (cursor_path == NULL)
10149     return FALSE;
10150
10151   _gtk_tree_view_find_node (tree_view, cursor_path,
10152                             &cursor_tree, &cursor_node);
10153   if (cursor_tree == NULL)
10154     {
10155       gtk_tree_path_free (cursor_path);
10156       return FALSE;
10157     }
10158
10159   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10160                                             cursor_node,
10161                                             cursor_tree,
10162                                             cursor_path,
10163                                             GTK_TREE_SELECT_MODE_TOGGLE,
10164                                             FALSE);
10165
10166   /* We bail out if the original (tree, node) don't exist anymore after
10167    * handling the selection-changed callback.  We do return TRUE because
10168    * the key press has been handled at this point.
10169    */
10170   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10171
10172   if (cursor_tree != new_tree || cursor_node != new_node)
10173     return FALSE;
10174
10175   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10176
10177   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10178   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10179   gtk_tree_path_free (cursor_path);
10180
10181   return TRUE;
10182 }
10183
10184 static gboolean
10185 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10186                                                gboolean     logical,
10187                                                gboolean     expand,
10188                                                gboolean     open_all)
10189 {
10190   GtkTreePath *cursor_path = NULL;
10191   GtkRBTree *tree;
10192   GtkRBNode *node;
10193
10194   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10195     return FALSE;
10196
10197   cursor_path = NULL;
10198   if (tree_view->priv->cursor)
10199     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10200
10201   if (cursor_path == NULL)
10202     return FALSE;
10203
10204   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10205     return FALSE;
10206
10207   /* Don't handle the event if we aren't an expander */
10208   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10209     return FALSE;
10210
10211   if (!logical
10212       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10213     expand = !expand;
10214
10215   if (expand)
10216     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10217   else
10218     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10219
10220   gtk_tree_path_free (cursor_path);
10221
10222   return TRUE;
10223 }
10224
10225 static gboolean
10226 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10227 {
10228   GtkRBTree *cursor_tree = NULL;
10229   GtkRBNode *cursor_node = NULL;
10230   GtkTreePath *cursor_path = NULL;
10231   GdkModifierType state;
10232
10233   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10234     return FALSE;
10235
10236   cursor_path = NULL;
10237   if (tree_view->priv->cursor)
10238     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10239
10240   if (cursor_path == NULL)
10241     return FALSE;
10242
10243   _gtk_tree_view_find_node (tree_view, cursor_path,
10244                             &cursor_tree, &cursor_node);
10245   if (cursor_tree == NULL)
10246     {
10247       gtk_tree_path_free (cursor_path);
10248       return FALSE;
10249     }
10250
10251   if (gtk_get_current_event_state (&state))
10252     {
10253       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10254         tree_view->priv->ctrl_pressed = TRUE;
10255     }
10256
10257   if (cursor_tree->parent_node)
10258     {
10259       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10260       cursor_node = cursor_tree->parent_node;
10261       cursor_tree = cursor_tree->parent_tree;
10262
10263       gtk_tree_path_up (cursor_path);
10264
10265       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10266     }
10267
10268   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10269
10270   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10271   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10272   gtk_tree_path_free (cursor_path);
10273
10274   tree_view->priv->ctrl_pressed = FALSE;
10275
10276   return TRUE;
10277 }
10278 static gboolean
10279 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10280 {
10281   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10282   tree_view->priv->typeselect_flush_timeout = 0;
10283
10284   return FALSE;
10285 }
10286
10287 /* Cut and paste from gtkwindow.c */
10288 static void
10289 send_focus_change (GtkWidget *widget,
10290                    gboolean   in)
10291 {
10292   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10293
10294   g_object_ref (widget);
10295    
10296  if (in)
10297     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10298   else
10299     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10300
10301   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10302   fevent->focus_change.window = g_object_ref (widget->window);
10303   fevent->focus_change.in = in;
10304   
10305   gtk_widget_event (widget, fevent);
10306   
10307   g_object_notify (G_OBJECT (widget), "has-focus");
10308
10309   g_object_unref (widget);
10310   gdk_event_free (fevent);
10311 }
10312
10313 static void
10314 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10315 {
10316   GtkWidget *frame, *vbox, *toplevel;
10317   GdkScreen *screen;
10318
10319   if (tree_view->priv->search_custom_entry_set)
10320     return;
10321
10322   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10323   screen = gtk_widget_get_screen (tree_view);
10324
10325    if (tree_view->priv->search_window != NULL)
10326      {
10327        if (GTK_WINDOW (toplevel)->group)
10328          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10329                                       GTK_WINDOW (tree_view->priv->search_window));
10330        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10331          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10332                                          GTK_WINDOW (tree_view->priv->search_window));
10333        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10334        return;
10335      }
10336    
10337   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10338   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10339
10340   if (GTK_WINDOW (toplevel)->group)
10341     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10342                                  GTK_WINDOW (tree_view->priv->search_window));
10343
10344   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10345                             GDK_WINDOW_TYPE_HINT_UTILITY);
10346   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10347   g_signal_connect (tree_view->priv->search_window, "delete-event",
10348                     G_CALLBACK (gtk_tree_view_search_delete_event),
10349                     tree_view);
10350   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10351                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10352                     tree_view);
10353   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10354                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10355                     tree_view);
10356   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10357                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10358                     tree_view);
10359
10360   frame = gtk_frame_new (NULL);
10361   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10362   gtk_widget_show (frame);
10363   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10364
10365   vbox = gtk_vbox_new (FALSE, 0);
10366   gtk_widget_show (vbox);
10367   gtk_container_add (GTK_CONTAINER (frame), vbox);
10368   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10369
10370   /* add entry */
10371   tree_view->priv->search_entry = gtk_entry_new ();
10372   gtk_widget_show (tree_view->priv->search_entry);
10373   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10374                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10375                     tree_view);
10376   g_signal_connect (tree_view->priv->search_entry,
10377                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10378                     tree_view);
10379   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10380                     "preedit-changed",
10381                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10382                     tree_view);
10383   gtk_container_add (GTK_CONTAINER (vbox),
10384                      tree_view->priv->search_entry);
10385
10386   gtk_widget_realize (tree_view->priv->search_entry);
10387 }
10388
10389 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10390  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10391  */
10392 static gboolean
10393 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10394                                              gboolean     keybinding)
10395 {
10396   /* We only start interactive search if we have focus or the columns
10397    * have focus.  If one of our children have focus, we don't want to
10398    * start the search.
10399    */
10400   GList *list;
10401   gboolean found_focus = FALSE;
10402   GtkWidgetClass *entry_parent_class;
10403   
10404   if (!tree_view->priv->enable_search && !keybinding)
10405     return FALSE;
10406
10407   if (tree_view->priv->search_custom_entry_set)
10408     return FALSE;
10409
10410   if (tree_view->priv->search_window != NULL &&
10411       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10412     return TRUE;
10413
10414   for (list = tree_view->priv->columns; list; list = list->next)
10415     {
10416       GtkTreeViewColumn *column;
10417
10418       column = list->data;
10419       if (! column->visible)
10420         continue;
10421
10422       if (GTK_WIDGET_HAS_FOCUS (column->button))
10423         {
10424           found_focus = TRUE;
10425           break;
10426         }
10427     }
10428   
10429   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10430     found_focus = TRUE;
10431
10432   if (!found_focus)
10433     return FALSE;
10434
10435   if (tree_view->priv->search_column < 0)
10436     return FALSE;
10437
10438   gtk_tree_view_ensure_interactive_directory (tree_view);
10439
10440   if (keybinding)
10441     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10442
10443   /* done, show it */
10444   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10445   gtk_widget_show (tree_view->priv->search_window);
10446   if (tree_view->priv->search_entry_changed_id == 0)
10447     {
10448       tree_view->priv->search_entry_changed_id =
10449         g_signal_connect (tree_view->priv->search_entry, "changed",
10450                           G_CALLBACK (gtk_tree_view_search_init),
10451                           tree_view);
10452     }
10453
10454   tree_view->priv->typeselect_flush_timeout =
10455     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10456                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10457                    tree_view);
10458
10459   /* Grab focus will select all the text.  We don't want that to happen, so we
10460    * call the parent instance and bypass the selection change.  This is probably
10461    * really non-kosher. */
10462   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10463   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10464
10465   /* send focus-in event */
10466   send_focus_change (tree_view->priv->search_entry, TRUE);
10467
10468   /* search first matching iter */
10469   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10470
10471   return TRUE;
10472 }
10473
10474 static gboolean
10475 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10476 {
10477   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10478 }
10479
10480 /* this function returns the new width of the column being resized given
10481  * the column and x position of the cursor; the x cursor position is passed
10482  * in as a pointer and automagicly corrected if it's beyond min/max limits
10483  */
10484 static gint
10485 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10486                                 gint       i,
10487                                 gint      *x)
10488 {
10489   GtkTreeViewColumn *column;
10490   gint width;
10491   gboolean rtl;
10492
10493   /* first translate the x position from widget->window
10494    * to clist->clist_window
10495    */
10496   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10497   column = g_list_nth (tree_view->priv->columns, i)->data;
10498   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10499  
10500   /* Clamp down the value */
10501   if (column->min_width == -1)
10502     width = MAX (column->button->requisition.width,
10503                  width);
10504   else
10505     width = MAX (column->min_width,
10506                  width);
10507   if (column->max_width != -1)
10508     width = MIN (width, column->max_width);
10509
10510   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10511  
10512   return width;
10513 }
10514
10515
10516 /* FIXME this adjust_allocation is a big cut-and-paste from
10517  * GtkCList, needs to be some "official" way to do this
10518  * factored out.
10519  */
10520 typedef struct
10521 {
10522   GdkWindow *window;
10523   int dx;
10524   int dy;
10525 } ScrollData;
10526
10527 /* The window to which widget->window is relative */
10528 #define ALLOCATION_WINDOW(widget)               \
10529    (GTK_WIDGET_NO_WINDOW (widget) ?             \
10530     (widget)->window :                          \
10531      gdk_window_get_parent ((widget)->window))
10532
10533 static void
10534 adjust_allocation_recurse (GtkWidget *widget,
10535                            gpointer   data)
10536 {
10537   ScrollData *scroll_data = data;
10538
10539   /* Need to really size allocate instead of just poking
10540    * into widget->allocation if the widget is not realized.
10541    * FIXME someone figure out why this was.
10542    */
10543   if (!GTK_WIDGET_REALIZED (widget))
10544     {
10545       if (GTK_WIDGET_VISIBLE (widget))
10546         {
10547           GdkRectangle tmp_rectangle = widget->allocation;
10548           tmp_rectangle.x += scroll_data->dx;
10549           tmp_rectangle.y += scroll_data->dy;
10550           
10551           gtk_widget_size_allocate (widget, &tmp_rectangle);
10552         }
10553     }
10554   else
10555     {
10556       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10557         {
10558           widget->allocation.x += scroll_data->dx;
10559           widget->allocation.y += scroll_data->dy;
10560           
10561           if (GTK_IS_CONTAINER (widget))
10562             gtk_container_forall (GTK_CONTAINER (widget),
10563                                   adjust_allocation_recurse,
10564                                   data);
10565         }
10566     }
10567 }
10568
10569 static void
10570 adjust_allocation (GtkWidget *widget,
10571                    int        dx,
10572                    int        dy)
10573 {
10574   ScrollData scroll_data;
10575
10576   if (GTK_WIDGET_REALIZED (widget))
10577     scroll_data.window = ALLOCATION_WINDOW (widget);
10578   else
10579     scroll_data.window = NULL;
10580     
10581   scroll_data.dx = dx;
10582   scroll_data.dy = dy;
10583   
10584   adjust_allocation_recurse (widget, &scroll_data);
10585 }
10586
10587 /* Callbacks */
10588 static void
10589 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10590                                   GtkTreeView   *tree_view)
10591 {
10592   if (GTK_WIDGET_REALIZED (tree_view))
10593     {
10594       gint dy;
10595         
10596       gdk_window_move (tree_view->priv->bin_window,
10597                        - tree_view->priv->hadjustment->value,
10598                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10599       gdk_window_move (tree_view->priv->header_window,
10600                        - tree_view->priv->hadjustment->value,
10601                        0);
10602       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10603       if (dy && tree_view->priv->edited_column)
10604         {
10605           if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10606             {
10607               GList *list;
10608               GtkWidget *widget;
10609               GtkTreeViewChild *child = NULL;
10610
10611               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10612               adjust_allocation (widget, 0, dy); 
10613               
10614               for (list = tree_view->priv->children; list; list = list->next)
10615                 {
10616                   child = (GtkTreeViewChild *)list->data;
10617                   if (child->widget == widget)
10618                     {
10619                       child->y += dy;
10620                       break;
10621                     }
10622                 }
10623             }
10624         }
10625       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10626
10627       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10628         {
10629           /* update our dy and top_row */
10630           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10631
10632           if (!tree_view->priv->in_top_row_to_dy)
10633             gtk_tree_view_dy_to_top_row (tree_view);
10634         }
10635     }
10636 }
10637
10638 \f
10639
10640 /* Public methods
10641  */
10642
10643 /**
10644  * gtk_tree_view_new:
10645  *
10646  * Creates a new #GtkTreeView widget.
10647  *
10648  * Return value: A newly created #GtkTreeView widget.
10649  **/
10650 GtkWidget *
10651 gtk_tree_view_new (void)
10652 {
10653   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10654 }
10655
10656 /**
10657  * gtk_tree_view_new_with_model:
10658  * @model: the model.
10659  *
10660  * Creates a new #GtkTreeView widget with the model initialized to @model.
10661  *
10662  * Return value: A newly created #GtkTreeView widget.
10663  **/
10664 GtkWidget *
10665 gtk_tree_view_new_with_model (GtkTreeModel *model)
10666 {
10667   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10668 }
10669
10670 /* Public Accessors
10671  */
10672
10673 /**
10674  * gtk_tree_view_get_model:
10675  * @tree_view: a #GtkTreeView
10676  *
10677  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10678  * model is unset.
10679  *
10680  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10681  **/
10682 GtkTreeModel *
10683 gtk_tree_view_get_model (GtkTreeView *tree_view)
10684 {
10685   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10686
10687   return tree_view->priv->model;
10688 }
10689
10690 /**
10691  * gtk_tree_view_set_model:
10692  * @tree_view: A #GtkTreeNode.
10693  * @model: The model.
10694  *
10695  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10696  * set, it will remove it before setting the new model.  If @model is %NULL, 
10697  * then it will unset the old model.
10698  **/
10699 void
10700 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10701                          GtkTreeModel *model)
10702 {
10703   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10704
10705   if (model != NULL)
10706     g_return_if_fail (GTK_IS_TREE_MODEL (model));
10707
10708   if (model == tree_view->priv->model)
10709     return;
10710
10711   if (tree_view->priv->scroll_to_path)
10712     {
10713       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10714       tree_view->priv->scroll_to_path = NULL;
10715     }
10716
10717   if (tree_view->priv->model)
10718     {
10719       GList *tmplist = tree_view->priv->columns;
10720
10721       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10722       gtk_tree_view_stop_editing (tree_view, TRUE);
10723
10724       remove_expand_collapse_timeout (tree_view);
10725
10726       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10727                                             gtk_tree_view_row_changed,
10728                                             tree_view);
10729       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10730                                             gtk_tree_view_row_inserted,
10731                                             tree_view);
10732       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10733                                             gtk_tree_view_row_has_child_toggled,
10734                                             tree_view);
10735       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10736                                             gtk_tree_view_row_deleted,
10737                                             tree_view);
10738       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10739                                             gtk_tree_view_rows_reordered,
10740                                             tree_view);
10741
10742       for (; tmplist; tmplist = tmplist->next)
10743         _gtk_tree_view_column_unset_model (tmplist->data,
10744                                            tree_view->priv->model);
10745
10746       if (tree_view->priv->tree)
10747         gtk_tree_view_free_rbtree (tree_view);
10748
10749       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10750       tree_view->priv->drag_dest_row = NULL;
10751       gtk_tree_row_reference_free (tree_view->priv->cursor);
10752       tree_view->priv->cursor = NULL;
10753       gtk_tree_row_reference_free (tree_view->priv->anchor);
10754       tree_view->priv->anchor = NULL;
10755       gtk_tree_row_reference_free (tree_view->priv->top_row);
10756       tree_view->priv->top_row = NULL;
10757       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
10758       tree_view->priv->last_button_press = NULL;
10759       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
10760       tree_view->priv->last_button_press_2 = NULL;
10761       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10762       tree_view->priv->scroll_to_path = NULL;
10763
10764       tree_view->priv->scroll_to_column = NULL;
10765
10766       g_object_unref (tree_view->priv->model);
10767
10768       tree_view->priv->search_column = -1;
10769       tree_view->priv->fixed_height_check = 0;
10770       tree_view->priv->fixed_height = -1;
10771       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10772     }
10773
10774   tree_view->priv->model = model;
10775
10776   if (tree_view->priv->model)
10777     {
10778       gint i;
10779       GtkTreePath *path;
10780       GtkTreeIter iter;
10781       GtkTreeModelFlags flags;
10782
10783       if (tree_view->priv->search_column == -1)
10784         {
10785           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10786             {
10787               GType type = gtk_tree_model_get_column_type (model, i);
10788
10789               if (g_value_type_transformable (type, G_TYPE_STRING))
10790                 {
10791                   tree_view->priv->search_column = i;
10792                   break;
10793                 }
10794             }
10795         }
10796
10797       g_object_ref (tree_view->priv->model);
10798       g_signal_connect (tree_view->priv->model,
10799                         "row-changed",
10800                         G_CALLBACK (gtk_tree_view_row_changed),
10801                         tree_view);
10802       g_signal_connect (tree_view->priv->model,
10803                         "row-inserted",
10804                         G_CALLBACK (gtk_tree_view_row_inserted),
10805                         tree_view);
10806       g_signal_connect (tree_view->priv->model,
10807                         "row-has-child-toggled",
10808                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10809                         tree_view);
10810       g_signal_connect (tree_view->priv->model,
10811                         "row-deleted",
10812                         G_CALLBACK (gtk_tree_view_row_deleted),
10813                         tree_view);
10814       g_signal_connect (tree_view->priv->model,
10815                         "rows-reordered",
10816                         G_CALLBACK (gtk_tree_view_rows_reordered),
10817                         tree_view);
10818
10819       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10820       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10821         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10822       else
10823         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10824
10825       path = gtk_tree_path_new_first ();
10826       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10827         {
10828           tree_view->priv->tree = _gtk_rbtree_new ();
10829           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10830         }
10831       gtk_tree_path_free (path);
10832
10833       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10834       install_presize_handler (tree_view);
10835     }
10836
10837   g_object_notify (G_OBJECT (tree_view), "model");
10838
10839   if (tree_view->priv->selection)
10840   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10841
10842   if (GTK_WIDGET_REALIZED (tree_view))
10843     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10844 }
10845
10846 /**
10847  * gtk_tree_view_get_selection:
10848  * @tree_view: A #GtkTreeView.
10849  *
10850  * Gets the #GtkTreeSelection associated with @tree_view.
10851  *
10852  * Return value: A #GtkTreeSelection object.
10853  **/
10854 GtkTreeSelection *
10855 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10856 {
10857   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10858
10859   return tree_view->priv->selection;
10860 }
10861
10862 /**
10863  * gtk_tree_view_get_hadjustment:
10864  * @tree_view: A #GtkTreeView
10865  *
10866  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10867  *
10868  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10869  * used.
10870  **/
10871 GtkAdjustment *
10872 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10873 {
10874   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10875
10876   if (tree_view->priv->hadjustment == NULL)
10877     gtk_tree_view_set_hadjustment (tree_view, NULL);
10878
10879   return tree_view->priv->hadjustment;
10880 }
10881
10882 /**
10883  * gtk_tree_view_set_hadjustment:
10884  * @tree_view: A #GtkTreeView
10885  * @adjustment: The #GtkAdjustment to set, or %NULL
10886  *
10887  * Sets the #GtkAdjustment for the current horizontal aspect.
10888  **/
10889 void
10890 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10891                                GtkAdjustment *adjustment)
10892 {
10893   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10894
10895   gtk_tree_view_set_adjustments (tree_view,
10896                                  adjustment,
10897                                  tree_view->priv->vadjustment);
10898
10899   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10900 }
10901
10902 /**
10903  * gtk_tree_view_get_vadjustment:
10904  * @tree_view: A #GtkTreeView
10905  *
10906  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10907  *
10908  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10909  * used.
10910  **/
10911 GtkAdjustment *
10912 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10913 {
10914   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10915
10916   if (tree_view->priv->vadjustment == NULL)
10917     gtk_tree_view_set_vadjustment (tree_view, NULL);
10918
10919   return tree_view->priv->vadjustment;
10920 }
10921
10922 /**
10923  * gtk_tree_view_set_vadjustment:
10924  * @tree_view: A #GtkTreeView
10925  * @adjustment: The #GtkAdjustment to set, or %NULL
10926  *
10927  * Sets the #GtkAdjustment for the current vertical aspect.
10928  **/
10929 void
10930 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10931                                GtkAdjustment *adjustment)
10932 {
10933   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10934
10935   gtk_tree_view_set_adjustments (tree_view,
10936                                  tree_view->priv->hadjustment,
10937                                  adjustment);
10938
10939   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10940 }
10941
10942 /* Column and header operations */
10943
10944 /**
10945  * gtk_tree_view_get_headers_visible:
10946  * @tree_view: A #GtkTreeView.
10947  *
10948  * Returns %TRUE if the headers on the @tree_view are visible.
10949  *
10950  * Return value: Whether the headers are visible or not.
10951  **/
10952 gboolean
10953 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10954 {
10955   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10956
10957   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10958 }
10959
10960 /**
10961  * gtk_tree_view_set_headers_visible:
10962  * @tree_view: A #GtkTreeView.
10963  * @headers_visible: %TRUE if the headers are visible
10964  *
10965  * Sets the visibility state of the headers.
10966  **/
10967 void
10968 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10969                                    gboolean     headers_visible)
10970 {
10971   gint x, y;
10972   GList *list;
10973   GtkTreeViewColumn *column;
10974
10975   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10976
10977   headers_visible = !! headers_visible;
10978
10979   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10980     return;
10981
10982   if (headers_visible)
10983     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10984   else
10985     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10986
10987   if (GTK_WIDGET_REALIZED (tree_view))
10988     {
10989       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
10990       if (headers_visible)
10991         {
10992           gdk_window_move_resize (tree_view->priv->bin_window, x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view), tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
10993
10994           if (GTK_WIDGET_MAPPED (tree_view))
10995             gtk_tree_view_map_buttons (tree_view);
10996         }
10997       else
10998         {
10999           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11000
11001           for (list = tree_view->priv->columns; list; list = list->next)
11002             {
11003               column = list->data;
11004               gtk_widget_unmap (column->button);
11005             }
11006           gdk_window_hide (tree_view->priv->header_window);
11007         }
11008     }
11009
11010   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11011   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11012   tree_view->priv->vadjustment->lower = 0;
11013   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11014   gtk_adjustment_changed (tree_view->priv->vadjustment);
11015
11016   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11017
11018   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11019 }
11020
11021 /**
11022  * gtk_tree_view_columns_autosize:
11023  * @tree_view: A #GtkTreeView.
11024  *
11025  * Resizes all columns to their optimal width. Only works after the
11026  * treeview has been realized.
11027  **/
11028 void
11029 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11030 {
11031   gboolean dirty = FALSE;
11032   GList *list;
11033   GtkTreeViewColumn *column;
11034
11035   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11036
11037   for (list = tree_view->priv->columns; list; list = list->next)
11038     {
11039       column = list->data;
11040       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11041         continue;
11042       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11043       dirty = TRUE;
11044     }
11045
11046   if (dirty)
11047     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11048 }
11049
11050 /**
11051  * gtk_tree_view_set_headers_clickable:
11052  * @tree_view: A #GtkTreeView.
11053  * @setting: %TRUE if the columns are clickable.
11054  *
11055  * Allow the column title buttons to be clicked.
11056  **/
11057 void
11058 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11059                                      gboolean   setting)
11060 {
11061   GList *list;
11062
11063   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11064
11065   for (list = tree_view->priv->columns; list; list = list->next)
11066     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11067
11068   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11069 }
11070
11071
11072 /**
11073  * gtk_tree_view_get_headers_clickable:
11074  * @tree_view: A #GtkTreeView.
11075  *
11076  * Returns whether all header columns are clickable.
11077  *
11078  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11079  *
11080  * Since: 2.10
11081  **/
11082 gboolean 
11083 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11084 {
11085   GList *list;
11086   
11087   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11088
11089   for (list = tree_view->priv->columns; list; list = list->next)
11090     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11091       return FALSE;
11092
11093   return TRUE;
11094 }
11095
11096 /**
11097  * gtk_tree_view_set_rules_hint
11098  * @tree_view: a #GtkTreeView
11099  * @setting: %TRUE if the tree requires reading across rows
11100  *
11101  * This function tells GTK+ that the user interface for your
11102  * application requires users to read across tree rows and associate
11103  * cells with one another. By default, GTK+ will then render the tree
11104  * with alternating row colors. Do <emphasis>not</emphasis> use it
11105  * just because you prefer the appearance of the ruled tree; that's a
11106  * question for the theme. Some themes will draw tree rows in
11107  * alternating colors even when rules are turned off, and users who
11108  * prefer that appearance all the time can choose those themes. You
11109  * should call this function only as a <emphasis>semantic</emphasis>
11110  * hint to the theme engine that your tree makes alternating colors
11111  * useful from a functional standpoint (since it has lots of columns,
11112  * generally).
11113  *
11114  **/
11115 void
11116 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11117                               gboolean      setting)
11118 {
11119   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11120
11121   setting = setting != FALSE;
11122
11123   if (tree_view->priv->has_rules != setting)
11124     {
11125       tree_view->priv->has_rules = setting;
11126       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11127     }
11128
11129   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11130 }
11131
11132 /**
11133  * gtk_tree_view_get_rules_hint
11134  * @tree_view: a #GtkTreeView
11135  *
11136  * Gets the setting set by gtk_tree_view_set_rules_hint().
11137  *
11138  * Return value: %TRUE if rules are useful for the user of this tree
11139  **/
11140 gboolean
11141 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11142 {
11143   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11144
11145   return tree_view->priv->has_rules;
11146 }
11147
11148 /* Public Column functions
11149  */
11150
11151 /**
11152  * gtk_tree_view_append_column:
11153  * @tree_view: A #GtkTreeView.
11154  * @column: The #GtkTreeViewColumn to add.
11155  *
11156  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11157  * mode enabled, then @column must have its "sizing" property set to be
11158  * GTK_TREE_VIEW_COLUMN_FIXED.
11159  *
11160  * Return value: The number of columns in @tree_view after appending.
11161  **/
11162 gint
11163 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11164                              GtkTreeViewColumn *column)
11165 {
11166   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11167   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11168   g_return_val_if_fail (column->tree_view == NULL, -1);
11169
11170   return gtk_tree_view_insert_column (tree_view, column, -1);
11171 }
11172
11173
11174 /**
11175  * gtk_tree_view_remove_column:
11176  * @tree_view: A #GtkTreeView.
11177  * @column: The #GtkTreeViewColumn to remove.
11178  *
11179  * Removes @column from @tree_view.
11180  *
11181  * Return value: The number of columns in @tree_view after removing.
11182  **/
11183 gint
11184 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11185                              GtkTreeViewColumn *column)
11186 {
11187   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11188   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11189   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11190
11191   if (tree_view->priv->focus_column == column)
11192     tree_view->priv->focus_column = NULL;
11193
11194   if (tree_view->priv->edited_column == column)
11195     {
11196       gtk_tree_view_stop_editing (tree_view, TRUE);
11197
11198       /* no need to, but just to be sure ... */
11199       tree_view->priv->edited_column = NULL;
11200     }
11201
11202   g_signal_handlers_disconnect_by_func (column,
11203                                         G_CALLBACK (column_sizing_notify),
11204                                         tree_view);
11205
11206   _gtk_tree_view_column_unset_tree_view (column);
11207
11208   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11209   tree_view->priv->n_columns--;
11210
11211   if (GTK_WIDGET_REALIZED (tree_view))
11212     {
11213       GList *list;
11214
11215       _gtk_tree_view_column_unrealize_button (column);
11216       for (list = tree_view->priv->columns; list; list = list->next)
11217         {
11218           GtkTreeViewColumn *tmp_column;
11219
11220           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11221           if (tmp_column->visible)
11222             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11223         }
11224
11225       if (tree_view->priv->n_columns == 0 &&
11226           gtk_tree_view_get_headers_visible (tree_view))
11227         gdk_window_hide (tree_view->priv->header_window);
11228
11229       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11230     }
11231
11232   g_object_unref (column);
11233   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11234
11235   return tree_view->priv->n_columns;
11236 }
11237
11238 /**
11239  * gtk_tree_view_insert_column:
11240  * @tree_view: A #GtkTreeView.
11241  * @column: The #GtkTreeViewColumn to be inserted.
11242  * @position: The position to insert @column in.
11243  *
11244  * This inserts the @column into the @tree_view at @position.  If @position is
11245  * -1, then the column is inserted at the end. If @tree_view has
11246  * "fixed_height" mode enabled, then @column must have its "sizing" property
11247  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11248  *
11249  * Return value: The number of columns in @tree_view after insertion.
11250  **/
11251 gint
11252 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11253                              GtkTreeViewColumn *column,
11254                              gint               position)
11255 {
11256   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11257   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11258   g_return_val_if_fail (column->tree_view == NULL, -1);
11259
11260   if (tree_view->priv->fixed_height_mode)
11261     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11262                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11263
11264   g_object_ref_sink (column);
11265
11266   if (tree_view->priv->n_columns == 0 &&
11267       GTK_WIDGET_REALIZED (tree_view) &&
11268       gtk_tree_view_get_headers_visible (tree_view))
11269     {
11270       gdk_window_show (tree_view->priv->header_window);
11271     }
11272
11273   g_signal_connect (column, "notify::sizing",
11274                     G_CALLBACK (column_sizing_notify), tree_view);
11275
11276   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11277                                             column, position);
11278   tree_view->priv->n_columns++;
11279
11280   _gtk_tree_view_column_set_tree_view (column, tree_view);
11281
11282   if (GTK_WIDGET_REALIZED (tree_view))
11283     {
11284       GList *list;
11285
11286       _gtk_tree_view_column_realize_button (column);
11287
11288       for (list = tree_view->priv->columns; list; list = list->next)
11289         {
11290           column = GTK_TREE_VIEW_COLUMN (list->data);
11291           if (column->visible)
11292             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11293         }
11294       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11295     }
11296
11297   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11298
11299   return tree_view->priv->n_columns;
11300 }
11301
11302 /**
11303  * gtk_tree_view_insert_column_with_attributes:
11304  * @tree_view: A #GtkTreeView
11305  * @position: The position to insert the new column in.
11306  * @title: The title to set the header to.
11307  * @cell: The #GtkCellRenderer.
11308  * @Varargs: A %NULL-terminated list of attributes.
11309  *
11310  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11311  * @position.  If @position is -1, then the newly created column is inserted at
11312  * the end.  The column is initialized with the attributes given. If @tree_view
11313  * has "fixed_height" mode enabled, then the new column will have its sizing
11314  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11315  *
11316  * Return value: The number of columns in @tree_view after insertion.
11317  **/
11318 gint
11319 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11320                                              gint             position,
11321                                              const gchar     *title,
11322                                              GtkCellRenderer *cell,
11323                                              ...)
11324 {
11325   GtkTreeViewColumn *column;
11326   gchar *attribute;
11327   va_list args;
11328   gint column_id;
11329
11330   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11331
11332   column = gtk_tree_view_column_new ();
11333   if (tree_view->priv->fixed_height_mode)
11334     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11335
11336   gtk_tree_view_column_set_title (column, title);
11337   gtk_tree_view_column_pack_start (column, cell, TRUE);
11338
11339   va_start (args, cell);
11340
11341   attribute = va_arg (args, gchar *);
11342
11343   while (attribute != NULL)
11344     {
11345       column_id = va_arg (args, gint);
11346       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11347       attribute = va_arg (args, gchar *);
11348     }
11349
11350   va_end (args);
11351
11352   gtk_tree_view_insert_column (tree_view, column, position);
11353
11354   return tree_view->priv->n_columns;
11355 }
11356
11357 /**
11358  * gtk_tree_view_insert_column_with_data_func:
11359  * @tree_view: a #GtkTreeView
11360  * @position: Position to insert, -1 for append
11361  * @title: column title
11362  * @cell: cell renderer for column
11363  * @func: function to set attributes of cell renderer
11364  * @data: data for @func
11365  * @dnotify: destroy notifier for @data
11366  *
11367  * Convenience function that inserts a new column into the #GtkTreeView
11368  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11369  * attributes (normally using data from the model). See also
11370  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11371  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11372  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11373  *
11374  * Return value: number of columns in the tree view post-insert
11375  **/
11376 gint
11377 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11378                                              gint                       position,
11379                                              const gchar               *title,
11380                                              GtkCellRenderer           *cell,
11381                                              GtkTreeCellDataFunc        func,
11382                                              gpointer                   data,
11383                                              GDestroyNotify             dnotify)
11384 {
11385   GtkTreeViewColumn *column;
11386
11387   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11388
11389   column = gtk_tree_view_column_new ();
11390   if (tree_view->priv->fixed_height_mode)
11391     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11392
11393   gtk_tree_view_column_set_title (column, title);
11394   gtk_tree_view_column_pack_start (column, cell, TRUE);
11395   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11396
11397   gtk_tree_view_insert_column (tree_view, column, position);
11398
11399   return tree_view->priv->n_columns;
11400 }
11401
11402 /**
11403  * gtk_tree_view_get_column:
11404  * @tree_view: A #GtkTreeView.
11405  * @n: The position of the column, counting from 0.
11406  *
11407  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11408  *
11409  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11410  * range of columns.
11411  **/
11412 GtkTreeViewColumn *
11413 gtk_tree_view_get_column (GtkTreeView *tree_view,
11414                           gint         n)
11415 {
11416   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11417
11418   if (n < 0 || n >= tree_view->priv->n_columns)
11419     return NULL;
11420
11421   if (tree_view->priv->columns == NULL)
11422     return NULL;
11423
11424   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11425 }
11426
11427 /**
11428  * gtk_tree_view_get_columns:
11429  * @tree_view: A #GtkTreeView
11430  *
11431  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11432  * The returned list must be freed with g_list_free ().
11433  *
11434  * Return value: A list of #GtkTreeViewColumn s
11435  **/
11436 GList *
11437 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11438 {
11439   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11440
11441   return g_list_copy (tree_view->priv->columns);
11442 }
11443
11444 /**
11445  * gtk_tree_view_move_column_after:
11446  * @tree_view: A #GtkTreeView
11447  * @column: The #GtkTreeViewColumn to be moved.
11448  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
11449  *
11450  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11451  * @column is placed in the first position.
11452  **/
11453 void
11454 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11455                                  GtkTreeViewColumn *column,
11456                                  GtkTreeViewColumn *base_column)
11457 {
11458   GList *column_list_el, *base_el = NULL;
11459
11460   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11461
11462   column_list_el = g_list_find (tree_view->priv->columns, column);
11463   g_return_if_fail (column_list_el != NULL);
11464
11465   if (base_column)
11466     {
11467       base_el = g_list_find (tree_view->priv->columns, base_column);
11468       g_return_if_fail (base_el != NULL);
11469     }
11470
11471   if (column_list_el->prev == base_el)
11472     return;
11473
11474   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11475   if (base_el == NULL)
11476     {
11477       column_list_el->prev = NULL;
11478       column_list_el->next = tree_view->priv->columns;
11479       if (column_list_el->next)
11480         column_list_el->next->prev = column_list_el;
11481       tree_view->priv->columns = column_list_el;
11482     }
11483   else
11484     {
11485       column_list_el->prev = base_el;
11486       column_list_el->next = base_el->next;
11487       if (column_list_el->next)
11488         column_list_el->next->prev = column_list_el;
11489       base_el->next = column_list_el;
11490     }
11491
11492   if (GTK_WIDGET_REALIZED (tree_view))
11493     {
11494       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11495       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11496     }
11497
11498   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11499 }
11500
11501 /**
11502  * gtk_tree_view_set_expander_column:
11503  * @tree_view: A #GtkTreeView
11504  * @column: %NULL, or the column to draw the expander arrow at.
11505  *
11506  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11507  * If @column is %NULL, then the expander arrow is always at the first 
11508  * visible column.
11509  *
11510  * If you do not want expander arrow to appear in your tree, set the 
11511  * expander column to a hidden column.
11512  **/
11513 void
11514 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11515                                    GtkTreeViewColumn *column)
11516 {
11517   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11518   if (column != NULL)
11519     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
11520
11521   if (tree_view->priv->expander_column != column)
11522     {
11523       GList *list;
11524
11525       if (column)
11526         {
11527           /* Confirm that column is in tree_view */
11528           for (list = tree_view->priv->columns; list; list = list->next)
11529             if (list->data == column)
11530               break;
11531           g_return_if_fail (list != NULL);
11532         }
11533
11534       tree_view->priv->expander_column = column;
11535       g_object_notify (G_OBJECT (tree_view), "expander-column");
11536     }
11537 }
11538
11539 /**
11540  * gtk_tree_view_get_expander_column:
11541  * @tree_view: A #GtkTreeView
11542  *
11543  * Returns the column that is the current expander column.  This
11544  * column has the expander arrow drawn next to it.
11545  *
11546  * Return value: The expander column.
11547  **/
11548 GtkTreeViewColumn *
11549 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11550 {
11551   GList *list;
11552
11553   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11554
11555   for (list = tree_view->priv->columns; list; list = list->next)
11556     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11557       return (GtkTreeViewColumn *) list->data;
11558   return NULL;
11559 }
11560
11561
11562 /**
11563  * gtk_tree_view_set_column_drag_function:
11564  * @tree_view: A #GtkTreeView.
11565  * @func: A function to determine which columns are reorderable, or %NULL.
11566  * @user_data: User data to be passed to @func, or %NULL
11567  * @destroy: Destroy notifier for @user_data, or %NULL
11568  *
11569  * Sets a user function for determining where a column may be dropped when
11570  * dragged.  This function is called on every column pair in turn at the
11571  * beginning of a column drag to determine where a drop can take place.  The
11572  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11573  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11574  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11575  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11576  * @tree_view reverts to the default behavior of allowing all columns to be
11577  * dropped everywhere.
11578  **/
11579 void
11580 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11581                                         GtkTreeViewColumnDropFunc  func,
11582                                         gpointer                   user_data,
11583                                         GDestroyNotify             destroy)
11584 {
11585   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11586
11587   if (tree_view->priv->column_drop_func_data_destroy)
11588     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11589
11590   tree_view->priv->column_drop_func = func;
11591   tree_view->priv->column_drop_func_data = user_data;
11592   tree_view->priv->column_drop_func_data_destroy = destroy;
11593 }
11594
11595 /**
11596  * gtk_tree_view_scroll_to_point:
11597  * @tree_view: a #GtkTreeView
11598  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11599  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11600  *
11601  * Scrolls the tree view such that the top-left corner of the visible
11602  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11603  * in tree coordinates.  The @tree_view must be realized before
11604  * this function is called.  If it isn't, you probably want to be
11605  * using gtk_tree_view_scroll_to_cell().
11606  *
11607  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11608  **/
11609 void
11610 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11611                                gint         tree_x,
11612                                gint         tree_y)
11613 {
11614   GtkAdjustment *hadj;
11615   GtkAdjustment *vadj;
11616
11617   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11618   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11619
11620   hadj = tree_view->priv->hadjustment;
11621   vadj = tree_view->priv->vadjustment;
11622
11623   if (tree_x != -1)
11624     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11625   if (tree_y != -1)
11626     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11627 }
11628
11629 /**
11630  * gtk_tree_view_scroll_to_cell:
11631  * @tree_view: A #GtkTreeView.
11632  * @path: The path of the row to move to, or %NULL.
11633  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
11634  * @use_align: whether to use alignment arguments, or %FALSE.
11635  * @row_align: The vertical alignment of the row specified by @path.
11636  * @col_align: The horizontal alignment of the column specified by @column.
11637  *
11638  * Moves the alignments of @tree_view to the position specified by @column and
11639  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11640  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11641  * or @path need to be non-%NULL.  @row_align determines where the row is
11642  * placed, and @col_align determines where @column is placed.  Both are expected
11643  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11644  * right/bottom alignment, 0.5 means center.
11645  *
11646  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11647  * tree does the minimum amount of work to scroll the cell onto the screen.
11648  * This means that the cell will be scrolled to the edge closest to its current
11649  * position.  If the cell is currently visible on the screen, nothing is done.
11650  *
11651  * This function only works if the model is set, and @path is a valid row on the
11652  * model.  If the model changes before the @tree_view is realized, the centered
11653  * path will be modified to reflect this change.
11654  **/
11655 void
11656 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11657                               GtkTreePath       *path,
11658                               GtkTreeViewColumn *column,
11659                               gboolean           use_align,
11660                               gfloat             row_align,
11661                               gfloat             col_align)
11662 {
11663   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11664   g_return_if_fail (tree_view->priv->model != NULL);
11665   g_return_if_fail (tree_view->priv->tree != NULL);
11666   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11667   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11668   g_return_if_fail (path != NULL || column != NULL);
11669
11670 #if 0
11671   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11672            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11673 #endif
11674   row_align = CLAMP (row_align, 0.0, 1.0);
11675   col_align = CLAMP (col_align, 0.0, 1.0);
11676
11677
11678   /* Note: Despite the benefits that come from having one code path for the
11679    * scrolling code, we short-circuit validate_visible_area's immplementation as
11680    * it is much slower than just going to the point.
11681    */
11682   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11683       ! GTK_WIDGET_REALIZED (tree_view) ||
11684       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11685       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11686     {
11687       if (tree_view->priv->scroll_to_path)
11688         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11689
11690       tree_view->priv->scroll_to_path = NULL;
11691       tree_view->priv->scroll_to_column = NULL;
11692
11693       if (path)
11694         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11695       if (column)
11696         tree_view->priv->scroll_to_column = column;
11697       tree_view->priv->scroll_to_use_align = use_align;
11698       tree_view->priv->scroll_to_row_align = row_align;
11699       tree_view->priv->scroll_to_col_align = col_align;
11700
11701       install_presize_handler (tree_view);
11702     }
11703   else
11704     {
11705       GdkRectangle cell_rect;
11706       GdkRectangle vis_rect;
11707       gint dest_x, dest_y;
11708
11709       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11710       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11711
11712       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11713
11714       dest_x = vis_rect.x;
11715       dest_y = vis_rect.y;
11716
11717       if (column)
11718         {
11719           if (use_align)
11720             {
11721               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11722             }
11723           else
11724             {
11725               if (cell_rect.x < vis_rect.x)
11726                 dest_x = cell_rect.x;
11727               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11728                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11729             }
11730         }
11731
11732       if (path)
11733         {
11734           if (use_align)
11735             {
11736               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11737               dest_y = MAX (dest_y, 0);
11738             }
11739           else
11740             {
11741               if (cell_rect.y < vis_rect.y)
11742                 dest_y = cell_rect.y;
11743               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11744                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11745             }
11746         }
11747
11748       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11749     }
11750 }
11751
11752 /**
11753  * gtk_tree_view_row_activated:
11754  * @tree_view: A #GtkTreeView
11755  * @path: The #GtkTreePath to be activated.
11756  * @column: The #GtkTreeViewColumn to be activated.
11757  *
11758  * Activates the cell determined by @path and @column.
11759  **/
11760 void
11761 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11762                              GtkTreePath       *path,
11763                              GtkTreeViewColumn *column)
11764 {
11765   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11766
11767   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11768 }
11769
11770
11771 static void
11772 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11773                                           GtkRBNode *node,
11774                                           gpointer   data)
11775 {
11776   GtkTreeView *tree_view = data;
11777
11778   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11779       node->children)
11780     {
11781       GtkTreePath *path;
11782       GtkTreeIter iter;
11783
11784       path = _gtk_tree_view_find_path (tree_view, tree, node);
11785       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11786
11787       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11788
11789       gtk_tree_path_free (path);
11790     }
11791
11792   if (node->children)
11793     _gtk_rbtree_traverse (node->children,
11794                           node->children->root,
11795                           G_PRE_ORDER,
11796                           gtk_tree_view_expand_all_emission_helper,
11797                           tree_view);
11798 }
11799
11800 /**
11801  * gtk_tree_view_expand_all:
11802  * @tree_view: A #GtkTreeView.
11803  *
11804  * Recursively expands all nodes in the @tree_view.
11805  **/
11806 void
11807 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11808 {
11809   GtkTreePath *path;
11810   GtkRBTree *tree;
11811   GtkRBNode *node;
11812
11813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11814
11815   if (tree_view->priv->tree == NULL)
11816     return;
11817
11818   path = gtk_tree_path_new_first ();
11819   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11820
11821   while (node)
11822     {
11823       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11824       node = _gtk_rbtree_next (tree, node);
11825       gtk_tree_path_next (path);
11826   }
11827
11828   gtk_tree_path_free (path);
11829 }
11830
11831 /* Timeout to animate the expander during expands and collapses */
11832 static gboolean
11833 expand_collapse_timeout (gpointer data)
11834 {
11835   return do_expand_collapse (data);
11836 }
11837
11838 static void
11839 add_expand_collapse_timeout (GtkTreeView *tree_view,
11840                              GtkRBTree   *tree,
11841                              GtkRBNode   *node,
11842                              gboolean     expand)
11843 {
11844   if (tree_view->priv->expand_collapse_timeout != 0)
11845     return;
11846
11847   tree_view->priv->expand_collapse_timeout =
11848       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11849   tree_view->priv->expanded_collapsed_tree = tree;
11850   tree_view->priv->expanded_collapsed_node = node;
11851
11852   if (expand)
11853     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11854   else
11855     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11856 }
11857
11858 static void
11859 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11860 {
11861   if (tree_view->priv->expand_collapse_timeout)
11862     {
11863       g_source_remove (tree_view->priv->expand_collapse_timeout);
11864       tree_view->priv->expand_collapse_timeout = 0;
11865     }
11866
11867   if (tree_view->priv->expanded_collapsed_node != NULL)
11868     {
11869       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11870       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11871
11872       tree_view->priv->expanded_collapsed_node = NULL;
11873     }
11874 }
11875
11876 static void
11877 cancel_arrow_animation (GtkTreeView *tree_view)
11878 {
11879   if (tree_view->priv->expand_collapse_timeout)
11880     {
11881       while (do_expand_collapse (tree_view));
11882
11883       remove_expand_collapse_timeout (tree_view);
11884     }
11885 }
11886
11887 static gboolean
11888 do_expand_collapse (GtkTreeView *tree_view)
11889 {
11890   GtkRBNode *node;
11891   GtkRBTree *tree;
11892   gboolean expanding;
11893   gboolean redraw;
11894
11895   redraw = FALSE;
11896   expanding = TRUE;
11897
11898   node = tree_view->priv->expanded_collapsed_node;
11899   tree = tree_view->priv->expanded_collapsed_tree;
11900
11901   if (node->children == NULL)
11902     expanding = FALSE;
11903
11904   if (expanding)
11905     {
11906       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11907         {
11908           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11909           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11910
11911           redraw = TRUE;
11912
11913         }
11914       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11915         {
11916           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11917
11918           redraw = TRUE;
11919         }
11920     }
11921   else
11922     {
11923       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11924         {
11925           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11926           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11927
11928           redraw = TRUE;
11929         }
11930       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11931         {
11932           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11933
11934           redraw = TRUE;
11935
11936         }
11937     }
11938
11939   if (redraw)
11940     {
11941       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11942
11943       return TRUE;
11944     }
11945
11946   return FALSE;
11947 }
11948
11949 /**
11950  * gtk_tree_view_collapse_all:
11951  * @tree_view: A #GtkTreeView.
11952  *
11953  * Recursively collapses all visible, expanded nodes in @tree_view.
11954  **/
11955 void
11956 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11957 {
11958   GtkRBTree *tree;
11959   GtkRBNode *node;
11960   GtkTreePath *path;
11961   gint *indices;
11962
11963   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11964
11965   if (tree_view->priv->tree == NULL)
11966     return;
11967
11968   path = gtk_tree_path_new ();
11969   gtk_tree_path_down (path);
11970   indices = gtk_tree_path_get_indices (path);
11971
11972   tree = tree_view->priv->tree;
11973   node = tree->root;
11974   while (node && node->left != tree->nil)
11975     node = node->left;
11976
11977   while (node)
11978     {
11979       if (node->children)
11980         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
11981       indices[0]++;
11982       node = _gtk_rbtree_next (tree, node);
11983     }
11984
11985   gtk_tree_path_free (path);
11986 }
11987
11988 /**
11989  * gtk_tree_view_expand_to_path:
11990  * @tree_view: A #GtkTreeView.
11991  * @path: path to a row.
11992  *
11993  * Expands the row at @path. This will also expand all parent rows of
11994  * @path as necessary.
11995  *
11996  * Since: 2.2
11997  **/
11998 void
11999 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12000                               GtkTreePath *path)
12001 {
12002   gint i, depth;
12003   gint *indices;
12004   GtkTreePath *tmp;
12005
12006   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12007   g_return_if_fail (path != NULL);
12008
12009   depth = gtk_tree_path_get_depth (path);
12010   indices = gtk_tree_path_get_indices (path);
12011
12012   tmp = gtk_tree_path_new ();
12013   g_return_if_fail (tmp != NULL);
12014
12015   for (i = 0; i < depth; i++)
12016     {
12017       gtk_tree_path_append_index (tmp, indices[i]);
12018       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12019     }
12020
12021   gtk_tree_path_free (tmp);
12022 }
12023
12024 /* FIXME the bool return values for expand_row and collapse_row are
12025  * not analagous; they should be TRUE if the row had children and
12026  * was not already in the requested state.
12027  */
12028
12029
12030 static gboolean
12031 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12032                                GtkTreePath *path,
12033                                GtkRBTree   *tree,
12034                                GtkRBNode   *node,
12035                                gboolean     open_all,
12036                                gboolean     animate)
12037 {
12038   GtkTreeIter iter;
12039   GtkTreeIter temp;
12040   gboolean expand;
12041
12042   if (animate)
12043     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12044                   "gtk-enable-animations", &animate,
12045                   NULL);
12046
12047   remove_auto_expand_timeout (tree_view);
12048
12049   if (node->children && !open_all)
12050     return FALSE;
12051
12052   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12053     return FALSE;
12054
12055   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12056   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12057     return FALSE;
12058
12059
12060    if (node->children && open_all)
12061     {
12062       gboolean retval = FALSE;
12063       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12064
12065       gtk_tree_path_append_index (tmp_path, 0);
12066       tree = node->children;
12067       node = tree->root;
12068       while (node->left != tree->nil)
12069         node = node->left;
12070       /* try to expand the children */
12071       do
12072         {
12073          gboolean t;
12074          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12075                                             TRUE, animate);
12076          if (t)
12077            retval = TRUE;
12078
12079          gtk_tree_path_next (tmp_path);
12080          node = _gtk_rbtree_next (tree, node);
12081        }
12082       while (node != NULL);
12083
12084       gtk_tree_path_free (tmp_path);
12085
12086       return retval;
12087     }
12088
12089   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12090
12091   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12092     return FALSE;
12093
12094   if (expand)
12095     return FALSE;
12096
12097   node->children = _gtk_rbtree_new ();
12098   node->children->parent_tree = tree;
12099   node->children->parent_node = node;
12100
12101   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12102
12103   gtk_tree_view_build_tree (tree_view,
12104                             node->children,
12105                             &temp,
12106                             gtk_tree_path_get_depth (path) + 1,
12107                             open_all);
12108
12109   remove_expand_collapse_timeout (tree_view);
12110
12111   if (animate)
12112     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12113
12114   install_presize_handler (tree_view);
12115
12116   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12117   if (open_all && node->children)
12118     {
12119       _gtk_rbtree_traverse (node->children,
12120                             node->children->root,
12121                             G_PRE_ORDER,
12122                             gtk_tree_view_expand_all_emission_helper,
12123                             tree_view);
12124     }
12125   return TRUE;
12126 }
12127
12128
12129 /**
12130  * gtk_tree_view_expand_row:
12131  * @tree_view: a #GtkTreeView
12132  * @path: path to a row
12133  * @open_all: whether to recursively expand, or just expand immediate children
12134  *
12135  * Opens the row so its children are visible.
12136  *
12137  * Return value: %TRUE if the row existed and had children
12138  **/
12139 gboolean
12140 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12141                           GtkTreePath *path,
12142                           gboolean     open_all)
12143 {
12144   GtkRBTree *tree;
12145   GtkRBNode *node;
12146
12147   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12148   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12149   g_return_val_if_fail (path != NULL, FALSE);
12150
12151   if (_gtk_tree_view_find_node (tree_view,
12152                                 path,
12153                                 &tree,
12154                                 &node))
12155     return FALSE;
12156
12157   if (tree != NULL)
12158     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12159   else
12160     return FALSE;
12161 }
12162
12163 static gboolean
12164 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12165                                  GtkTreePath *path,
12166                                  GtkRBTree   *tree,
12167                                  GtkRBNode   *node,
12168                                  gboolean     animate)
12169 {
12170   GtkTreeIter iter;
12171   GtkTreeIter children;
12172   gboolean collapse;
12173   gint x, y;
12174   GList *list;
12175   GdkWindow *child, *parent;
12176
12177   if (animate)
12178     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12179                   "gtk-enable-animations", &animate,
12180                   NULL);
12181
12182   remove_auto_expand_timeout (tree_view);
12183
12184   if (node->children == NULL)
12185     return FALSE;
12186
12187   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12188
12189   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12190
12191   if (collapse)
12192     return FALSE;
12193
12194   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12195    * a chance to prelight the correct node below */
12196
12197   if (tree_view->priv->prelight_tree)
12198     {
12199       GtkRBTree *parent_tree;
12200       GtkRBNode *parent_node;
12201
12202       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12203       parent_node = tree_view->priv->prelight_tree->parent_node;
12204       while (parent_tree)
12205         {
12206           if (parent_tree == tree && parent_node == node)
12207             {
12208               ensure_unprelighted (tree_view);
12209               break;
12210             }
12211           parent_node = parent_tree->parent_node;
12212           parent_tree = parent_tree->parent_tree;
12213         }
12214     }
12215
12216   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12217
12218   for (list = tree_view->priv->columns; list; list = list->next)
12219     {
12220       GtkTreeViewColumn *column = list->data;
12221
12222       if (column->visible == FALSE)
12223         continue;
12224       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12225         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12226     }
12227
12228   if (tree_view->priv->destroy_count_func)
12229     {
12230       GtkTreePath *child_path;
12231       gint child_count = 0;
12232       child_path = gtk_tree_path_copy (path);
12233       gtk_tree_path_down (child_path);
12234       if (node->children)
12235         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12236       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12237       gtk_tree_path_free (child_path);
12238     }
12239
12240   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12241     {
12242       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12243
12244       if (gtk_tree_path_is_ancestor (path, cursor_path))
12245         {
12246           gtk_tree_row_reference_free (tree_view->priv->cursor);
12247           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12248                                                                       tree_view->priv->model,
12249                                                                       path);
12250         }
12251       gtk_tree_path_free (cursor_path);
12252     }
12253
12254   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12255     {
12256       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12257       if (gtk_tree_path_is_ancestor (path, anchor_path))
12258         {
12259           gtk_tree_row_reference_free (tree_view->priv->anchor);
12260           tree_view->priv->anchor = NULL;
12261         }
12262       gtk_tree_path_free (anchor_path);
12263     }
12264
12265   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press))
12266     {
12267       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
12268       if (gtk_tree_path_is_ancestor (path, lsc))
12269         {
12270           gtk_tree_row_reference_free (tree_view->priv->last_button_press);
12271           tree_view->priv->last_button_press = NULL;
12272         }
12273       gtk_tree_path_free (lsc);
12274     }
12275
12276   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press_2))
12277     {
12278       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press_2);
12279       if (gtk_tree_path_is_ancestor (path, lsc))
12280         {
12281           gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
12282           tree_view->priv->last_button_press_2 = NULL;
12283         }
12284       gtk_tree_path_free (lsc);
12285     }
12286
12287   remove_expand_collapse_timeout (tree_view);
12288
12289   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12290     {
12291       _gtk_rbtree_remove (node->children);
12292       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12293     }
12294   else
12295     _gtk_rbtree_remove (node->children);
12296   
12297   if (animate)
12298     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12299   
12300   if (GTK_WIDGET_MAPPED (tree_view))
12301     {
12302       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12303     }
12304
12305   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12306
12307   if (GTK_WIDGET_MAPPED (tree_view))
12308     {
12309       /* now that we've collapsed all rows, we want to try to set the prelight
12310        * again. To do this, we fake a motion event and send it to ourselves. */
12311
12312       child = tree_view->priv->bin_window;
12313       parent = gdk_window_get_parent (child);
12314
12315       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12316         {
12317           GdkEventMotion event;
12318           gint child_x, child_y;
12319
12320           gdk_window_get_position (child, &child_x, &child_y);
12321
12322           event.window = tree_view->priv->bin_window;
12323           event.x = x - child_x;
12324           event.y = y - child_y;
12325
12326           /* despite the fact this isn't a real event, I'm almost positive it will
12327            * never trigger a drag event.  maybe_drag is the only function that uses
12328            * more than just event.x and event.y. */
12329           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12330         }
12331     }
12332
12333   return TRUE;
12334 }
12335
12336 /**
12337  * gtk_tree_view_collapse_row:
12338  * @tree_view: a #GtkTreeView
12339  * @path: path to a row in the @tree_view
12340  *
12341  * Collapses a row (hides its child rows, if they exist).
12342  *
12343  * Return value: %TRUE if the row was collapsed.
12344  **/
12345 gboolean
12346 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12347                             GtkTreePath *path)
12348 {
12349   GtkRBTree *tree;
12350   GtkRBNode *node;
12351
12352   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12353   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12354   g_return_val_if_fail (path != NULL, FALSE);
12355
12356   if (_gtk_tree_view_find_node (tree_view,
12357                                 path,
12358                                 &tree,
12359                                 &node))
12360     return FALSE;
12361
12362   if (tree == NULL || node->children == NULL)
12363     return FALSE;
12364
12365   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12366 }
12367
12368 static void
12369 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12370                                         GtkRBTree              *tree,
12371                                         GtkTreePath            *path,
12372                                         GtkTreeViewMappingFunc  func,
12373                                         gpointer                user_data)
12374 {
12375   GtkRBNode *node;
12376
12377   if (tree == NULL || tree->root == NULL)
12378     return;
12379
12380   node = tree->root;
12381
12382   while (node && node->left != tree->nil)
12383     node = node->left;
12384
12385   while (node)
12386     {
12387       if (node->children)
12388         {
12389           (* func) (tree_view, path, user_data);
12390           gtk_tree_path_down (path);
12391           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12392           gtk_tree_path_up (path);
12393         }
12394       gtk_tree_path_next (path);
12395       node = _gtk_rbtree_next (tree, node);
12396     }
12397 }
12398
12399 /**
12400  * gtk_tree_view_map_expanded_rows:
12401  * @tree_view: A #GtkTreeView
12402  * @func: A function to be called
12403  * @data: User data to be passed to the function.
12404  *
12405  * Calls @func on all expanded rows.
12406  **/
12407 void
12408 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12409                                  GtkTreeViewMappingFunc  func,
12410                                  gpointer                user_data)
12411 {
12412   GtkTreePath *path;
12413
12414   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12415   g_return_if_fail (func != NULL);
12416
12417   path = gtk_tree_path_new_first ();
12418
12419   gtk_tree_view_map_expanded_rows_helper (tree_view,
12420                                           tree_view->priv->tree,
12421                                           path, func, user_data);
12422
12423   gtk_tree_path_free (path);
12424 }
12425
12426 /**
12427  * gtk_tree_view_row_expanded:
12428  * @tree_view: A #GtkTreeView.
12429  * @path: A #GtkTreePath to test expansion state.
12430  *
12431  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12432  *
12433  * Return value: %TRUE if #path is expanded.
12434  **/
12435 gboolean
12436 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12437                             GtkTreePath *path)
12438 {
12439   GtkRBTree *tree;
12440   GtkRBNode *node;
12441
12442   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12443   g_return_val_if_fail (path != NULL, FALSE);
12444
12445   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12446
12447   if (node == NULL)
12448     return FALSE;
12449
12450   return (node->children != NULL);
12451 }
12452
12453 /**
12454  * gtk_tree_view_get_reorderable:
12455  * @tree_view: a #GtkTreeView
12456  *
12457  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12458  * gtk_tree_view_set_reorderable().
12459  *
12460  * Return value: %TRUE if the tree can be reordered.
12461  **/
12462 gboolean
12463 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12464 {
12465   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12466
12467   return tree_view->priv->reorderable;
12468 }
12469
12470 /**
12471  * gtk_tree_view_set_reorderable:
12472  * @tree_view: A #GtkTreeView.
12473  * @reorderable: %TRUE, if the tree can be reordered.
12474  *
12475  * This function is a convenience function to allow you to reorder
12476  * models that support the #GtkDragSourceIface and the
12477  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12478  * these.  If @reorderable is %TRUE, then the user can reorder the
12479  * model by dragging and dropping rows. The developer can listen to
12480  * these changes by connecting to the model's row_inserted and
12481  * row_deleted signals. The reordering is implemented by setting up
12482  * the tree view as a drag source and destination. Therefore, drag and
12483  * drop can not be used in a reorderable view for any other purpose.
12484  *
12485  * This function does not give you any degree of control over the order -- any
12486  * reordering is allowed.  If more control is needed, you should probably
12487  * handle drag and drop manually.
12488  **/
12489 void
12490 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12491                                gboolean     reorderable)
12492 {
12493   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12494
12495   reorderable = reorderable != FALSE;
12496
12497   if (tree_view->priv->reorderable == reorderable)
12498     return;
12499
12500   if (reorderable)
12501     {
12502       const GtkTargetEntry row_targets[] = {
12503         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12504       };
12505
12506       gtk_tree_view_enable_model_drag_source (tree_view,
12507                                               GDK_BUTTON1_MASK,
12508                                               row_targets,
12509                                               G_N_ELEMENTS (row_targets),
12510                                               GDK_ACTION_MOVE);
12511       gtk_tree_view_enable_model_drag_dest (tree_view,
12512                                             row_targets,
12513                                             G_N_ELEMENTS (row_targets),
12514                                             GDK_ACTION_MOVE);
12515     }
12516   else
12517     {
12518       gtk_tree_view_unset_rows_drag_source (tree_view);
12519       gtk_tree_view_unset_rows_drag_dest (tree_view);
12520     }
12521
12522   tree_view->priv->reorderable = reorderable;
12523
12524   g_object_notify (G_OBJECT (tree_view), "reorderable");
12525 }
12526
12527 static void
12528 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12529                                GtkTreePath     *path,
12530                                gboolean         clear_and_select,
12531                                gboolean         clamp_node)
12532 {
12533   GtkRBTree *tree = NULL;
12534   GtkRBNode *node = NULL;
12535
12536   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12537     {
12538       GtkTreePath *cursor_path;
12539       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12540       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12541       gtk_tree_path_free (cursor_path);
12542     }
12543
12544   gtk_tree_row_reference_free (tree_view->priv->cursor);
12545   tree_view->priv->cursor = NULL;
12546
12547   /* One cannot set the cursor on a separator. */
12548   if (!row_is_separator (tree_view, NULL, path))
12549     {
12550       tree_view->priv->cursor =
12551         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12552                                           tree_view->priv->model,
12553                                           path);
12554       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12555     }
12556
12557   if (tree != NULL)
12558     {
12559       GtkRBTree *new_tree = NULL;
12560       GtkRBNode *new_node = NULL;
12561
12562       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12563         {
12564           GtkTreeSelectMode mode = 0;
12565
12566           if (tree_view->priv->ctrl_pressed)
12567             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12568           if (tree_view->priv->shift_pressed)
12569             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12570
12571           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12572                                                     node, tree, path, mode,
12573                                                     FALSE);
12574         }
12575
12576       /* We have to re-find tree and node here again, somebody might have
12577        * cleared the node or the whole tree in the GtkTreeSelection::changed
12578        * callback. If the nodes differ we bail out here.
12579        */
12580       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12581
12582       if (tree != new_tree || node != new_node)
12583         return;
12584
12585       if (clamp_node)
12586         {
12587           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12588           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12589         }
12590     }
12591
12592   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12593 }
12594
12595 /**
12596  * gtk_tree_view_get_cursor:
12597  * @tree_view: A #GtkTreeView
12598  * @path: A pointer to be filled with the current cursor path, or %NULL
12599  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12600  *
12601  * Fills in @path and @focus_column with the current path and focus column.  If
12602  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12603  * currently has focus, then *@focus_column will be %NULL.
12604  *
12605  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12606  * you are done with it.
12607  **/
12608 void
12609 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12610                           GtkTreePath       **path,
12611                           GtkTreeViewColumn **focus_column)
12612 {
12613   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12614
12615   if (path)
12616     {
12617       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12618         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12619       else
12620         *path = NULL;
12621     }
12622
12623   if (focus_column)
12624     {
12625       *focus_column = tree_view->priv->focus_column;
12626     }
12627 }
12628
12629 /**
12630  * gtk_tree_view_set_cursor:
12631  * @tree_view: A #GtkTreeView
12632  * @path: A #GtkTreePath
12633  * @focus_column: A #GtkTreeViewColumn, or %NULL
12634  * @start_editing: %TRUE if the specified cell should start being edited.
12635  *
12636  * Sets the current keyboard focus to be at @path, and selects it.  This is
12637  * useful when you want to focus the user's attention on a particular row.  If
12638  * @focus_column is not %NULL, then focus is given to the column specified by 
12639  * it. Additionally, if @focus_column is specified, and @start_editing is 
12640  * %TRUE, then editing should be started in the specified cell.  
12641  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12642  * in order to give keyboard focus to the widget.  Please note that editing 
12643  * can only happen when the widget is realized.
12644  **/
12645 void
12646 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12647                           GtkTreePath       *path,
12648                           GtkTreeViewColumn *focus_column,
12649                           gboolean           start_editing)
12650 {
12651   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12652                                     NULL, start_editing);
12653 }
12654
12655 /**
12656  * gtk_tree_view_set_cursor_on_cell:
12657  * @tree_view: A #GtkTreeView
12658  * @path: A #GtkTreePath
12659  * @focus_column: A #GtkTreeViewColumn, or %NULL
12660  * @focus_cell: A #GtkCellRenderer, or %NULL
12661  * @start_editing: %TRUE if the specified cell should start being edited.
12662  *
12663  * Sets the current keyboard focus to be at @path, and selects it.  This is
12664  * useful when you want to focus the user's attention on a particular row.  If
12665  * @focus_column is not %NULL, then focus is given to the column specified by
12666  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12667  * contains 2 or more editable or activatable cells, then focus is given to
12668  * the cell specified by @focus_cell. Additionally, if @focus_column is
12669  * specified, and @start_editing is %TRUE, then editing should be started in
12670  * the specified cell.  This function is often followed by
12671  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12672  * widget.  Please note that editing can only happen when the widget is
12673  * realized.
12674  *
12675  * Since: 2.2
12676  **/
12677 void
12678 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12679                                   GtkTreePath       *path,
12680                                   GtkTreeViewColumn *focus_column,
12681                                   GtkCellRenderer   *focus_cell,
12682                                   gboolean           start_editing)
12683 {
12684   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12685   g_return_if_fail (tree_view->priv->tree != NULL);
12686   g_return_if_fail (path != NULL);
12687   if (focus_column)
12688     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
12689   if (focus_cell)
12690     {
12691       g_return_if_fail (focus_column);
12692       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12693     }
12694
12695   /* cancel the current editing, if it exists */
12696   if (tree_view->priv->edited_column &&
12697       tree_view->priv->edited_column->editable_widget)
12698     gtk_tree_view_stop_editing (tree_view, TRUE);
12699
12700   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12701
12702   if (focus_column && focus_column->visible)
12703     {
12704       GList *list;
12705       gboolean column_in_tree = FALSE;
12706
12707       for (list = tree_view->priv->columns; list; list = list->next)
12708         if (list->data == focus_column)
12709           {
12710             column_in_tree = TRUE;
12711             break;
12712           }
12713       g_return_if_fail (column_in_tree);
12714       tree_view->priv->focus_column = focus_column;
12715       if (focus_cell)
12716         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12717       if (start_editing)
12718         gtk_tree_view_start_editing (tree_view, path);
12719     }
12720 }
12721
12722 /**
12723  * gtk_tree_view_get_bin_window:
12724  * @tree_view: A #GtkTreeView
12725  * 
12726  * Returns the window that @tree_view renders to.  This is used primarily to
12727  * compare to <literal>event->window</literal> to confirm that the event on
12728  * @tree_view is on the right window.
12729  * 
12730  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12731  **/
12732 GdkWindow *
12733 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12734 {
12735   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12736
12737   return tree_view->priv->bin_window;
12738 }
12739
12740 /**
12741  * gtk_tree_view_get_path_at_pos:
12742  * @tree_view: A #GtkTreeView.
12743  * @x: The x position to be identified (relative to bin_window).
12744  * @y: The y position to be identified (relative to bin_window).
12745  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12746  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12747  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12748  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12749  *
12750  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12751  * (please see gtk_tree_view_get_bin_window()).
12752  * That is, @x and @y are relative to an events coordinates. @x and @y must
12753  * come from an event on the @tree_view only where <literal>event->window ==
12754  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12755  * things like popup menus. If @path is non-%NULL, then it will be filled
12756  * with the #GtkTreePath at that point.  This path should be freed with
12757  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12758  * with the column at that point.  @cell_x and @cell_y return the coordinates
12759  * relative to the cell background (i.e. the @background_area passed to
12760  * gtk_cell_renderer_render()).  This function is only meaningful if
12761  * @tree_view is realized.
12762  *
12763  * For converting widget coordinates (eg. the ones you get from
12764  * GtkWidget::query-tooltip), please see
12765  * gtk_tree_view_convert_widget_to_bin_window_coords().
12766  *
12767  * Return value: %TRUE if a row exists at that coordinate.
12768  **/
12769 gboolean
12770 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12771                                gint                x,
12772                                gint                y,
12773                                GtkTreePath       **path,
12774                                GtkTreeViewColumn **column,
12775                                gint               *cell_x,
12776                                gint               *cell_y)
12777 {
12778   GtkRBTree *tree;
12779   GtkRBNode *node;
12780   gint y_offset;
12781
12782   g_return_val_if_fail (tree_view != NULL, FALSE);
12783   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
12784
12785   if (path)
12786     *path = NULL;
12787   if (column)
12788     *column = NULL;
12789
12790   if (tree_view->priv->tree == NULL)
12791     return FALSE;
12792
12793   if (x > tree_view->priv->hadjustment->upper)
12794     return FALSE;
12795
12796   if (x < 0 || y < 0)
12797     return FALSE;
12798
12799   if (column || cell_x)
12800     {
12801       GtkTreeViewColumn *tmp_column;
12802       GtkTreeViewColumn *last_column = NULL;
12803       GList *list;
12804       gint remaining_x = x;
12805       gboolean found = FALSE;
12806       gboolean rtl;
12807
12808       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12809       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12810            list;
12811            list = (rtl ? list->prev : list->next))
12812         {
12813           tmp_column = list->data;
12814
12815           if (tmp_column->visible == FALSE)
12816             continue;
12817
12818           last_column = tmp_column;
12819           if (remaining_x <= tmp_column->width)
12820             {
12821               found = TRUE;
12822
12823               if (column)
12824                 *column = tmp_column;
12825
12826               if (cell_x)
12827                 *cell_x = remaining_x;
12828
12829               break;
12830             }
12831           remaining_x -= tmp_column->width;
12832         }
12833
12834       /* If found is FALSE and there is a last_column, then it the remainder
12835        * space is in that area
12836        */
12837       if (!found)
12838         {
12839           if (last_column)
12840             {
12841               if (column)
12842                 *column = last_column;
12843               
12844               if (cell_x)
12845                 *cell_x = last_column->width + remaining_x;
12846             }
12847           else
12848             {
12849               return FALSE;
12850             }
12851         }
12852     }
12853
12854   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12855                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12856                                       &tree, &node);
12857
12858   if (tree == NULL)
12859     return FALSE;
12860
12861   if (cell_y)
12862     *cell_y = y_offset;
12863
12864   if (path)
12865     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12866
12867   return TRUE;
12868 }
12869
12870
12871 /**
12872  * gtk_tree_view_get_cell_area:
12873  * @tree_view: a #GtkTreeView
12874  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12875  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12876  * @rect: rectangle to fill with cell rect
12877  *
12878  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12879  * row specified by @path and the column specified by @column.  If @path is
12880  * %NULL, or points to a path not currently displayed, the @y and @height fields
12881  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12882  * fields will be filled with 0.  The sum of all cell rects does not cover the
12883  * entire tree; there are extra pixels in between rows, for example. The
12884  * returned rectangle is equivalent to the @cell_area passed to
12885  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12886  * realized.
12887  **/
12888 void
12889 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12890                              GtkTreePath        *path,
12891                              GtkTreeViewColumn  *column,
12892                              GdkRectangle       *rect)
12893 {
12894   GtkRBTree *tree = NULL;
12895   GtkRBNode *node = NULL;
12896   gint vertical_separator;
12897   gint horizontal_separator;
12898
12899   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12900   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12901   g_return_if_fail (rect != NULL);
12902   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12903   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12904
12905   gtk_widget_style_get (GTK_WIDGET (tree_view),
12906                         "vertical-separator", &vertical_separator,
12907                         "horizontal-separator", &horizontal_separator,
12908                         NULL);
12909
12910   rect->x = 0;
12911   rect->y = 0;
12912   rect->width = 0;
12913   rect->height = 0;
12914
12915   if (column)
12916     {
12917       rect->x = column->button->allocation.x + horizontal_separator/2;
12918       rect->width = column->button->allocation.width - horizontal_separator;
12919     }
12920
12921   if (path)
12922     {
12923       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12924
12925       /* Get vertical coords */
12926       if ((!ret && tree == NULL) || ret)
12927         return;
12928
12929       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12930       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12931
12932       if (column &&
12933           gtk_tree_view_is_expander_column (tree_view, column))
12934         {
12935           gint depth = gtk_tree_path_get_depth (path);
12936           gboolean rtl;
12937
12938           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12939
12940           if (!rtl)
12941             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12942           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12943
12944           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12945             {
12946               if (!rtl)
12947                 rect->x += depth * tree_view->priv->expander_size;
12948               rect->width -= depth * tree_view->priv->expander_size;
12949             }
12950
12951           rect->width = MAX (rect->width, 0);
12952         }
12953     }
12954 }
12955
12956 /**
12957  * gtk_tree_view_get_background_area:
12958  * @tree_view: a #GtkTreeView
12959  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12960  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12961  * @rect: rectangle to fill with cell background rect
12962  *
12963  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12964  * row specified by @path and the column specified by @column.  If @path is
12965  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12966  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12967  * fields will be filled with 0.  The returned rectangle is equivalent to the
12968  * @background_area passed to gtk_cell_renderer_render().  These background
12969  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12970  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12971  * itself, excluding surrounding borders and the tree expander area.
12972  *
12973  **/
12974 void
12975 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12976                                    GtkTreePath        *path,
12977                                    GtkTreeViewColumn  *column,
12978                                    GdkRectangle       *rect)
12979 {
12980   GtkRBTree *tree = NULL;
12981   GtkRBNode *node = NULL;
12982
12983   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12984   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12985   g_return_if_fail (rect != NULL);
12986
12987   rect->x = 0;
12988   rect->y = 0;
12989   rect->width = 0;
12990   rect->height = 0;
12991
12992   if (path)
12993     {
12994       /* Get vertical coords */
12995
12996       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
12997           tree == NULL)
12998         return;
12999
13000       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13001
13002       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13003     }
13004
13005   if (column)
13006     {
13007       gint x2 = 0;
13008
13009       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13010       rect->width = x2 - rect->x;
13011     }
13012 }
13013
13014 /**
13015  * gtk_tree_view_get_visible_rect:
13016  * @tree_view: a #GtkTreeView
13017  * @visible_rect: rectangle to fill
13018  *
13019  * Fills @visible_rect with the currently-visible region of the
13020  * buffer, in tree coordinates. Convert to bin_window coordinates with
13021  * gtk_tree_view_convert_tree_to_bin_window_coords().
13022  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13023  * scrollable area of the tree.
13024  **/
13025 void
13026 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13027                                 GdkRectangle *visible_rect)
13028 {
13029   GtkWidget *widget;
13030
13031   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13032
13033   widget = GTK_WIDGET (tree_view);
13034
13035   if (visible_rect)
13036     {
13037       visible_rect->x = tree_view->priv->hadjustment->value;
13038       visible_rect->y = tree_view->priv->vadjustment->value;
13039       visible_rect->width = widget->allocation.width;
13040       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13041     }
13042 }
13043
13044 /**
13045  * gtk_tree_view_widget_to_tree_coords:
13046  * @tree_view: a #GtkTreeView
13047  * @wx: X coordinate relative to bin_window
13048  * @wy: Y coordinate relative to bin_window
13049  * @tx: return location for tree X coordinate
13050  * @ty: return location for tree Y coordinate
13051  *
13052  * Converts bin_window coordinates to coordinates for the
13053  * tree (the full scrollable area of the tree).
13054  *
13055  * Deprecated: 2.12: Due to historial reasons the name of this function is
13056  * incorrect.  For converting coordinates relative to the widget to
13057  * bin_window coordinates, please see
13058  * gtk_tree_view_convert_widget_to_bin_window_coords().
13059  *
13060  **/
13061 void
13062 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
13063                                       gint         wx,
13064                                       gint         wy,
13065                                       gint        *tx,
13066                                       gint        *ty)
13067 {
13068   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13069
13070   if (tx)
13071     *tx = wx + tree_view->priv->hadjustment->value;
13072   if (ty)
13073     *ty = wy + tree_view->priv->dy;
13074 }
13075
13076 /**
13077  * gtk_tree_view_tree_to_widget_coords:
13078  * @tree_view: a #GtkTreeView
13079  * @tx: tree X coordinate
13080  * @ty: tree Y coordinate
13081  * @wx: return location for X coordinate relative to bin_window
13082  * @wy: return location for Y coordinate relative to bin_window
13083  *
13084  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13085  * to bin_window coordinates.
13086  *
13087  * Deprecated: 2.12: Due to historial reasons the name of this function is
13088  * incorrect.  For converting bin_window coordinates to coordinates relative
13089  * to bin_window, please see
13090  * gtk_tree_view_convert_bin_window_to_widget_coords().
13091  *
13092  **/
13093 void
13094 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
13095                                      gint         tx,
13096                                      gint         ty,
13097                                      gint        *wx,
13098                                      gint        *wy)
13099 {
13100   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13101
13102   if (wx)
13103     *wx = tx - tree_view->priv->hadjustment->value;
13104   if (wy)
13105     *wy = ty - tree_view->priv->dy;
13106 }
13107
13108
13109 /**
13110  * gtk_tree_view_convert_widget_to_tree_coords:
13111  * @tree_view: a #GtkTreeView
13112  * @wx: X coordinate relative to the widget
13113  * @wy: Y coordinate relative to the widget
13114  * @tx: return location for tree X coordinate
13115  * @ty: return location for tree Y coordinate
13116  *
13117  * Converts widget coordinates to coordinates for the
13118  * tree (the full scrollable area of the tree).
13119  *
13120  * Since: 2.12
13121  **/
13122 void
13123 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13124                                              gint         wx,
13125                                              gint         wy,
13126                                              gint        *tx,
13127                                              gint        *ty)
13128 {
13129   gint x, y;
13130
13131   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13132
13133   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13134                                                      wx, wy,
13135                                                      &x, &y);
13136   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13137                                                    x, y,
13138                                                    tx, ty);
13139 }
13140
13141 /**
13142  * gtk_tree_view_convert_tree_to_widget_coords:
13143  * @tree_view: a #GtkTreeView
13144  * @tx: X coordinate relative to the tree
13145  * @ty: Y coordinate relative to the tree
13146  * @wx: return location for widget X coordinate
13147  * @wy: return location for widget Y coordinate
13148  *
13149  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13150  * to widget coordinates.
13151  *
13152  * Since: 2.12
13153  **/
13154 void
13155 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13156                                              gint         tx,
13157                                              gint         ty,
13158                                              gint        *wx,
13159                                              gint        *wy)
13160 {
13161   gint x, y;
13162
13163   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13164
13165   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13166                                                    tx, ty,
13167                                                    &x, &y);
13168   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13169                                                      x, y,
13170                                                      wx, wy);
13171 }
13172
13173 /**
13174  * gtk_tree_view_convert_widget_to_bin_window_coords:
13175  * @tree_view: a #GtkTreeView
13176  * @wx: X coordinate relative to the widget
13177  * @wy: Y coordinate relative to the widget
13178  * @bx: return location for bin_window X coordinate
13179  * @by: return location for bin_window Y coordinate
13180  *
13181  * Converts widget coordinates to coordinates for the bin_window
13182  * (see gtk_tree_view_get_bin_window()).
13183  *
13184  * Since: 2.12
13185  **/
13186 void
13187 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13188                                                    gint         wx,
13189                                                    gint         wy,
13190                                                    gint        *bx,
13191                                                    gint        *by)
13192 {
13193   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13194
13195   if (bx)
13196     *bx = wx + tree_view->priv->hadjustment->value;
13197   if (by)
13198     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13199 }
13200
13201 /**
13202  * gtk_tree_view_convert_bin_window_to_widget_coords:
13203  * @tree_view: a #GtkTreeView
13204  * @bx: bin_window X coordinate
13205  * @by: bin_window Y coordinate
13206  * @wx: return location for widget X coordinate
13207  * @wy: return location for widget Y coordinate
13208  *
13209  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13210  * to widget relative coordinates.
13211  *
13212  * Since: 2.12
13213  **/
13214 void
13215 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13216                                                    gint         bx,
13217                                                    gint         by,
13218                                                    gint        *wx,
13219                                                    gint        *wy)
13220 {
13221   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13222
13223   if (wx)
13224     *wx = bx - tree_view->priv->hadjustment->value;
13225   if (wy)
13226     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13227 }
13228
13229 /**
13230  * gtk_tree_view_convert_tree_to_bin_window_coords:
13231  * @tree_view: a #GtkTreeView
13232  * @tx: tree X coordinate
13233  * @ty: tree Y coordinate
13234  * @bx: return location for X coordinate relative to bin_window
13235  * @by: return location for Y coordinate relative to bin_window
13236  *
13237  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13238  * to bin_window coordinates.
13239  *
13240  * Since: 2.12
13241  **/
13242 void
13243 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13244                                                  gint         tx,
13245                                                  gint         ty,
13246                                                  gint        *bx,
13247                                                  gint        *by)
13248 {
13249   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13250
13251   if (bx)
13252     *bx = tx;
13253   if (by)
13254     *by = ty - tree_view->priv->dy;
13255 }
13256
13257 /**
13258  * gtk_tree_view_convert_bin_window_to_tree_coords:
13259  * @tree_view: a #GtkTreeView
13260  * @bx: X coordinate relative to bin_window
13261  * @by: Y coordinate relative to bin_window
13262  * @tx: return location for tree X coordinate
13263  * @ty: return location for tree Y coordinate
13264  *
13265  * Converts bin_window coordinates to coordinates for the
13266  * tree (the full scrollable area of the tree).
13267  *
13268  * Since: 2.12
13269  **/
13270 void
13271 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13272                                                  gint         bx,
13273                                                  gint         by,
13274                                                  gint        *tx,
13275                                                  gint        *ty)
13276 {
13277   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13278
13279   if (tx)
13280     *tx = bx;
13281   if (ty)
13282     *ty = by + tree_view->priv->dy;
13283 }
13284
13285
13286
13287 /**
13288  * gtk_tree_view_get_visible_range:
13289  * @tree_view: A #GtkTreeView
13290  * @start_path: Return location for start of region, or %NULL.
13291  * @end_path: Return location for end of region, or %NULL.
13292  *
13293  * Sets @start_path and @end_path to be the first and last visible path.
13294  * Note that there may be invisible paths in between.
13295  *
13296  * The paths should be freed with gtk_tree_path_free() after use.
13297  *
13298  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13299  *
13300  * Since: 2.8
13301  **/
13302 gboolean
13303 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13304                                  GtkTreePath **start_path,
13305                                  GtkTreePath **end_path)
13306 {
13307   GtkRBTree *tree;
13308   GtkRBNode *node;
13309   gboolean retval;
13310   
13311   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13312
13313   if (!tree_view->priv->tree)
13314     return FALSE;
13315
13316   retval = TRUE;
13317
13318   if (start_path)
13319     {
13320       _gtk_rbtree_find_offset (tree_view->priv->tree,
13321                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13322                                &tree, &node);
13323       if (node)
13324         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13325       else
13326         retval = FALSE;
13327     }
13328
13329   if (end_path)
13330     {
13331       gint y;
13332
13333       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13334         y = tree_view->priv->height - 1;
13335       else
13336         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13337
13338       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13339       if (node)
13340         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13341       else
13342         retval = FALSE;
13343     }
13344
13345   return retval;
13346 }
13347
13348 static void
13349 unset_reorderable (GtkTreeView *tree_view)
13350 {
13351   if (tree_view->priv->reorderable)
13352     {
13353       tree_view->priv->reorderable = FALSE;
13354       g_object_notify (G_OBJECT (tree_view), "reorderable");
13355     }
13356 }
13357
13358 /**
13359  * gtk_tree_view_enable_model_drag_source:
13360  * @tree_view: a #GtkTreeView
13361  * @start_button_mask: Mask of allowed buttons to start drag
13362  * @targets: the table of targets that the drag will support
13363  * @n_targets: the number of items in @targets
13364  * @actions: the bitmask of possible actions for a drag from this
13365  *    widget
13366  *
13367  * Turns @tree_view into a drag source for automatic DND. Calling this
13368  * method sets #GtkTreeView:reorderable to %FALSE.
13369  **/
13370 void
13371 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13372                                         GdkModifierType           start_button_mask,
13373                                         const GtkTargetEntry     *targets,
13374                                         gint                      n_targets,
13375                                         GdkDragAction             actions)
13376 {
13377   TreeViewDragInfo *di;
13378
13379   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13380
13381   gtk_drag_source_set (GTK_WIDGET (tree_view),
13382                        0,
13383                        targets,
13384                        n_targets,
13385                        actions);
13386
13387   di = ensure_info (tree_view);
13388
13389   di->start_button_mask = start_button_mask;
13390   di->source_actions = actions;
13391   di->source_set = TRUE;
13392
13393   unset_reorderable (tree_view);
13394 }
13395
13396 /**
13397  * gtk_tree_view_enable_model_drag_dest:
13398  * @tree_view: a #GtkTreeView
13399  * @targets: the table of targets that the drag will support
13400  * @n_targets: the number of items in @targets
13401  * @actions: the bitmask of possible actions for a drag from this
13402  *    widget
13403  * 
13404  * Turns @tree_view into a drop destination for automatic DND. Calling
13405  * this method sets #GtkTreeView:reorderable to %FALSE.
13406  **/
13407 void
13408 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13409                                       const GtkTargetEntry     *targets,
13410                                       gint                      n_targets,
13411                                       GdkDragAction             actions)
13412 {
13413   TreeViewDragInfo *di;
13414
13415   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13416
13417   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13418                      0,
13419                      targets,
13420                      n_targets,
13421                      actions);
13422
13423   di = ensure_info (tree_view);
13424   di->dest_set = TRUE;
13425
13426   unset_reorderable (tree_view);
13427 }
13428
13429 /**
13430  * gtk_tree_view_unset_rows_drag_source:
13431  * @tree_view: a #GtkTreeView
13432  *
13433  * Undoes the effect of
13434  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13435  * #GtkTreeView:reorderable to %FALSE.
13436  **/
13437 void
13438 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13439 {
13440   TreeViewDragInfo *di;
13441
13442   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13443
13444   di = get_info (tree_view);
13445
13446   if (di)
13447     {
13448       if (di->source_set)
13449         {
13450           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13451           di->source_set = FALSE;
13452         }
13453
13454       if (!di->dest_set && !di->source_set)
13455         remove_info (tree_view);
13456     }
13457   
13458   unset_reorderable (tree_view);
13459 }
13460
13461 /**
13462  * gtk_tree_view_unset_rows_drag_dest:
13463  * @tree_view: a #GtkTreeView
13464  *
13465  * Undoes the effect of
13466  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13467  * #GtkTreeView:reorderable to %FALSE.
13468  **/
13469 void
13470 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13471 {
13472   TreeViewDragInfo *di;
13473
13474   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13475
13476   di = get_info (tree_view);
13477
13478   if (di)
13479     {
13480       if (di->dest_set)
13481         {
13482           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13483           di->dest_set = FALSE;
13484         }
13485
13486       if (!di->dest_set && !di->source_set)
13487         remove_info (tree_view);
13488     }
13489
13490   unset_reorderable (tree_view);
13491 }
13492
13493 /**
13494  * gtk_tree_view_set_drag_dest_row:
13495  * @tree_view: a #GtkTreeView
13496  * @path: The path of the row to highlight, or %NULL.
13497  * @pos: Specifies whether to drop before, after or into the row
13498  * 
13499  * Sets the row that is highlighted for feedback.
13500  **/
13501 void
13502 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13503                                  GtkTreePath            *path,
13504                                  GtkTreeViewDropPosition pos)
13505 {
13506   GtkTreePath *current_dest;
13507
13508   /* Note; this function is exported to allow a custom DND
13509    * implementation, so it can't touch TreeViewDragInfo
13510    */
13511
13512   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13513
13514   current_dest = NULL;
13515
13516   if (tree_view->priv->drag_dest_row)
13517     {
13518       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13519       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13520     }
13521
13522   /* special case a drop on an empty model */
13523   tree_view->priv->empty_view_drop = 0;
13524
13525   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13526       && gtk_tree_path_get_depth (path) == 1
13527       && gtk_tree_path_get_indices (path)[0] == 0)
13528     {
13529       gint n_children;
13530
13531       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13532                                                    NULL);
13533
13534       if (!n_children)
13535         tree_view->priv->empty_view_drop = 1;
13536     }
13537
13538   tree_view->priv->drag_dest_pos = pos;
13539
13540   if (path)
13541     {
13542       tree_view->priv->drag_dest_row =
13543         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13544       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13545     }
13546   else
13547     tree_view->priv->drag_dest_row = NULL;
13548
13549   if (current_dest)
13550     {
13551       GtkRBTree *tree, *new_tree;
13552       GtkRBNode *node, *new_node;
13553
13554       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13555       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13556
13557       if (tree && node)
13558         {
13559           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13560           if (new_tree && new_node)
13561             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13562
13563           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13564           if (new_tree && new_node)
13565             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13566         }
13567       gtk_tree_path_free (current_dest);
13568     }
13569 }
13570
13571 /**
13572  * gtk_tree_view_get_drag_dest_row:
13573  * @tree_view: a #GtkTreeView
13574  * @path: Return location for the path of the highlighted row, or %NULL.
13575  * @pos: Return location for the drop position, or %NULL
13576  * 
13577  * Gets information about the row that is highlighted for feedback.
13578  **/
13579 void
13580 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13581                                  GtkTreePath             **path,
13582                                  GtkTreeViewDropPosition  *pos)
13583 {
13584   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13585
13586   if (path)
13587     {
13588       if (tree_view->priv->drag_dest_row)
13589         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13590       else
13591         {
13592           if (tree_view->priv->empty_view_drop)
13593             *path = gtk_tree_path_new_from_indices (0, -1);
13594           else
13595             *path = NULL;
13596         }
13597     }
13598
13599   if (pos)
13600     *pos = tree_view->priv->drag_dest_pos;
13601 }
13602
13603 /**
13604  * gtk_tree_view_get_dest_row_at_pos:
13605  * @tree_view: a #GtkTreeView
13606  * @drag_x: the position to determine the destination row for
13607  * @drag_y: the position to determine the destination row for
13608  * @path: Return location for the path of the highlighted row, or %NULL.
13609  * @pos: Return location for the drop position, or %NULL
13610  * 
13611  * Determines the destination row for a given position.  @drag_x and
13612  * @drag_y are expected to be in widget coordinates.
13613  * 
13614  * Return value: whether there is a row at the given position.
13615  **/
13616 gboolean
13617 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13618                                    gint                     drag_x,
13619                                    gint                     drag_y,
13620                                    GtkTreePath            **path,
13621                                    GtkTreeViewDropPosition *pos)
13622 {
13623   gint cell_y;
13624   gint bin_x, bin_y;
13625   gdouble offset_into_row;
13626   gdouble third;
13627   GdkRectangle cell;
13628   GtkTreeViewColumn *column = NULL;
13629   GtkTreePath *tmp_path = NULL;
13630
13631   /* Note; this function is exported to allow a custom DND
13632    * implementation, so it can't touch TreeViewDragInfo
13633    */
13634
13635   g_return_val_if_fail (tree_view != NULL, FALSE);
13636   g_return_val_if_fail (drag_x >= 0, FALSE);
13637   g_return_val_if_fail (drag_y >= 0, FALSE);
13638   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
13639
13640
13641   if (path)
13642     *path = NULL;
13643
13644   if (tree_view->priv->tree == NULL)
13645     return FALSE;
13646
13647   /* If in the top third of a row, we drop before that row; if
13648    * in the bottom third, drop after that row; if in the middle,
13649    * and the row has children, drop into the row.
13650    */
13651   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13652                                                      &bin_x, &bin_y);
13653
13654   if (!gtk_tree_view_get_path_at_pos (tree_view,
13655                                       bin_x,
13656                                       bin_y,
13657                                       &tmp_path,
13658                                       &column,
13659                                       NULL,
13660                                       &cell_y))
13661     return FALSE;
13662
13663   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13664                                      &cell);
13665
13666   offset_into_row = cell_y;
13667
13668   if (path)
13669     *path = tmp_path;
13670   else
13671     gtk_tree_path_free (tmp_path);
13672
13673   tmp_path = NULL;
13674
13675   third = cell.height / 3.0;
13676
13677   if (pos)
13678     {
13679       if (offset_into_row < third)
13680         {
13681           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13682         }
13683       else if (offset_into_row < (cell.height / 2.0))
13684         {
13685           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13686         }
13687       else if (offset_into_row < third * 2.0)
13688         {
13689           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13690         }
13691       else
13692         {
13693           *pos = GTK_TREE_VIEW_DROP_AFTER;
13694         }
13695     }
13696
13697   return TRUE;
13698 }
13699
13700
13701
13702 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13703 /**
13704  * gtk_tree_view_create_row_drag_icon:
13705  * @tree_view: a #GtkTreeView
13706  * @path: a #GtkTreePath in @tree_view
13707  *
13708  * Creates a #GdkPixmap representation of the row at @path.  
13709  * This image is used for a drag icon.
13710  *
13711  * Return value: a newly-allocated pixmap of the drag icon.
13712  **/
13713 GdkPixmap *
13714 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13715                                     GtkTreePath  *path)
13716 {
13717   GtkTreeIter   iter;
13718   GtkRBTree    *tree;
13719   GtkRBNode    *node;
13720   gint cell_offset;
13721   GList *list;
13722   GdkRectangle background_area;
13723   GdkRectangle expose_area;
13724   GtkWidget *widget;
13725   gint depth;
13726   /* start drawing inside the black outline */
13727   gint x = 1, y = 1;
13728   GdkDrawable *drawable;
13729   gint bin_window_width;
13730   gboolean is_separator = FALSE;
13731   gboolean rtl;
13732
13733   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13734   g_return_val_if_fail (path != NULL, NULL);
13735
13736   widget = GTK_WIDGET (tree_view);
13737
13738   if (!GTK_WIDGET_REALIZED (tree_view))
13739     return NULL;
13740
13741   depth = gtk_tree_path_get_depth (path);
13742
13743   _gtk_tree_view_find_node (tree_view,
13744                             path,
13745                             &tree,
13746                             &node);
13747
13748   if (tree == NULL)
13749     return NULL;
13750
13751   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13752                                 &iter,
13753                                 path))
13754     return NULL;
13755   
13756   is_separator = row_is_separator (tree_view, &iter, NULL);
13757
13758   cell_offset = x;
13759
13760   background_area.y = y;
13761   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13762
13763   gdk_drawable_get_size (tree_view->priv->bin_window,
13764                          &bin_window_width, NULL);
13765
13766   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13767                              bin_window_width + 2,
13768                              background_area.height + 2,
13769                              -1);
13770
13771   expose_area.x = 0;
13772   expose_area.y = 0;
13773   expose_area.width = bin_window_width + 2;
13774   expose_area.height = background_area.height + 2;
13775
13776   gdk_draw_rectangle (drawable,
13777                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13778                       TRUE,
13779                       0, 0,
13780                       bin_window_width + 2,
13781                       background_area.height + 2);
13782
13783   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13784
13785   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13786       list;
13787       list = (rtl ? list->prev : list->next))
13788     {
13789       GtkTreeViewColumn *column = list->data;
13790       GdkRectangle cell_area;
13791       gint vertical_separator;
13792
13793       if (!column->visible)
13794         continue;
13795
13796       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13797                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13798                                                node->children?TRUE:FALSE);
13799
13800       background_area.x = cell_offset;
13801       background_area.width = column->width;
13802
13803       gtk_widget_style_get (widget,
13804                             "vertical-separator", &vertical_separator,
13805                             NULL);
13806
13807       cell_area = background_area;
13808
13809       cell_area.y += vertical_separator / 2;
13810       cell_area.height -= vertical_separator;
13811
13812       if (gtk_tree_view_is_expander_column (tree_view, column))
13813         {
13814           if (!rtl)
13815             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13816           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13817
13818           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13819             {
13820               if (!rtl)
13821                 cell_area.x += depth * tree_view->priv->expander_size;
13822               cell_area.width -= depth * tree_view->priv->expander_size;
13823             }
13824         }
13825
13826       if (gtk_tree_view_column_cell_is_visible (column))
13827         {
13828           if (is_separator)
13829             gtk_paint_hline (widget->style,
13830                              drawable,
13831                              GTK_STATE_NORMAL,
13832                              &cell_area,
13833                              widget,
13834                              NULL,
13835                              cell_area.x,
13836                              cell_area.x + cell_area.width,
13837                              cell_area.y + cell_area.height / 2);
13838           else
13839             _gtk_tree_view_column_cell_render (column,
13840                                                drawable,
13841                                                &background_area,
13842                                                &cell_area,
13843                                                &expose_area,
13844                                                0);
13845         }
13846       cell_offset += column->width;
13847     }
13848
13849   gdk_draw_rectangle (drawable,
13850                       widget->style->black_gc,
13851                       FALSE,
13852                       0, 0,
13853                       bin_window_width + 1,
13854                       background_area.height + 1);
13855
13856   return drawable;
13857 }
13858
13859
13860 /**
13861  * gtk_tree_view_set_destroy_count_func:
13862  * @tree_view: A #GtkTreeView
13863  * @func: Function to be called when a view row is destroyed, or %NULL
13864  * @data: User data to be passed to @func, or %NULL
13865  * @destroy: Destroy notifier for @data, or %NULL
13866  *
13867  * This function should almost never be used.  It is meant for private use by
13868  * ATK for determining the number of visible children that are removed when the
13869  * user collapses a row, or a row is deleted.
13870  **/
13871 void
13872 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13873                                       GtkTreeDestroyCountFunc  func,
13874                                       gpointer                 data,
13875                                       GDestroyNotify           destroy)
13876 {
13877   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13878
13879   if (tree_view->priv->destroy_count_destroy)
13880     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13881
13882   tree_view->priv->destroy_count_func = func;
13883   tree_view->priv->destroy_count_data = data;
13884   tree_view->priv->destroy_count_destroy = destroy;
13885 }
13886
13887
13888 /*
13889  * Interactive search
13890  */
13891
13892 /**
13893  * gtk_tree_view_set_enable_search:
13894  * @tree_view: A #GtkTreeView
13895  * @enable_search: %TRUE, if the user can search interactively
13896  *
13897  * If @enable_search is set, then the user can type in text to search through
13898  * the tree interactively (this is sometimes called "typeahead find").
13899  * 
13900  * Note that even if this is %FALSE, the user can still initiate a search 
13901  * using the "start-interactive-search" key binding.
13902  */
13903 void
13904 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13905                                  gboolean     enable_search)
13906 {
13907   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13908
13909   enable_search = !!enable_search;
13910   
13911   if (tree_view->priv->enable_search != enable_search)
13912     {
13913        tree_view->priv->enable_search = enable_search;
13914        g_object_notify (G_OBJECT (tree_view), "enable-search");
13915     }
13916 }
13917
13918 /**
13919  * gtk_tree_view_get_enable_search:
13920  * @tree_view: A #GtkTreeView
13921  *
13922  * Returns whether or not the tree allows to start interactive searching 
13923  * by typing in text.
13924  *
13925  * Return value: whether or not to let the user search interactively
13926  */
13927 gboolean
13928 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13929 {
13930   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13931
13932   return tree_view->priv->enable_search;
13933 }
13934
13935
13936 /**
13937  * gtk_tree_view_get_search_column:
13938  * @tree_view: A #GtkTreeView
13939  *
13940  * Gets the column searched on by the interactive search code.
13941  *
13942  * Return value: the column the interactive search code searches in.
13943  */
13944 gint
13945 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13946 {
13947   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13948
13949   return (tree_view->priv->search_column);
13950 }
13951
13952 /**
13953  * gtk_tree_view_set_search_column:
13954  * @tree_view: A #GtkTreeView
13955  * @column: the column of the model to search in, or -1 to disable searching
13956  *
13957  * Sets @column as the column where the interactive search code should
13958  * search in for the current model. 
13959  * 
13960  * If the search column is set, users can use the "start-interactive-search"
13961  * key binding to bring up search popup. The enable-search property controls
13962  * whether simply typing text will also start an interactive search.
13963  *
13964  * Note that @column refers to a column of the current model. The search 
13965  * column is reset to -1 when the model is changed.
13966  */
13967 void
13968 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13969                                  gint         column)
13970 {
13971   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13972   g_return_if_fail (column >= -1);
13973
13974   if (tree_view->priv->search_column == column)
13975     return;
13976
13977   tree_view->priv->search_column = column;
13978   g_object_notify (G_OBJECT (tree_view), "search-column");
13979 }
13980
13981 /**
13982  * gtk_tree_view_get_search_equal_func:
13983  * @tree_view: A #GtkTreeView
13984  *
13985  * Returns the compare function currently in use.
13986  *
13987  * Return value: the currently used compare function for the search code.
13988  */
13989
13990 GtkTreeViewSearchEqualFunc
13991 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13992 {
13993   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13994
13995   return tree_view->priv->search_equal_func;
13996 }
13997
13998 /**
13999  * gtk_tree_view_set_search_equal_func:
14000  * @tree_view: A #GtkTreeView
14001  * @search_equal_func: the compare function to use during the search
14002  * @search_user_data: user data to pass to @search_equal_func, or %NULL
14003  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
14004  *
14005  * Sets the compare function for the interactive search capabilities; note
14006  * that somewhat like strcmp() returning 0 for equality
14007  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14008  **/
14009 void
14010 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14011                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14012                                      gpointer                    search_user_data,
14013                                      GDestroyNotify              search_destroy)
14014 {
14015   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14016   g_return_if_fail (search_equal_func != NULL);
14017
14018   if (tree_view->priv->search_destroy)
14019     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14020
14021   tree_view->priv->search_equal_func = search_equal_func;
14022   tree_view->priv->search_user_data = search_user_data;
14023   tree_view->priv->search_destroy = search_destroy;
14024   if (tree_view->priv->search_equal_func == NULL)
14025     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14026 }
14027
14028 /**
14029  * gtk_tree_view_get_search_entry:
14030  * @tree_view: A #GtkTreeView
14031  *
14032  * Returns the #GtkEntry which is currently in use as interactive search
14033  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14034  * will be returned.
14035  *
14036  * Return value: the entry currently in use as search entry.
14037  *
14038  * Since: 2.10
14039  */
14040 GtkEntry *
14041 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14042 {
14043   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14044
14045   if (tree_view->priv->search_custom_entry_set)
14046     return GTK_ENTRY (tree_view->priv->search_entry);
14047
14048   return NULL;
14049 }
14050
14051 /**
14052  * gtk_tree_view_set_search_entry:
14053  * @tree_view: A #GtkTreeView
14054  * @entry: the entry the interactive search code of @tree_view should use or %NULL
14055  *
14056  * Sets the entry which the interactive search code will use for this
14057  * @tree_view.  This is useful when you want to provide a search entry
14058  * in our interface at all time at a fixed position.  Passing %NULL for
14059  * @entry will make the interactive search code use the built-in popup
14060  * entry again.
14061  *
14062  * Since: 2.10
14063  */
14064 void
14065 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14066                                 GtkEntry    *entry)
14067 {
14068   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14069   if (entry != NULL)
14070     g_return_if_fail (GTK_IS_ENTRY (entry));
14071
14072   if (tree_view->priv->search_custom_entry_set)
14073     {
14074       if (tree_view->priv->search_entry_changed_id)
14075         {
14076           g_signal_handler_disconnect (tree_view->priv->search_entry,
14077                                        tree_view->priv->search_entry_changed_id);
14078           tree_view->priv->search_entry_changed_id = 0;
14079         }
14080       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14081                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14082                                             tree_view);
14083
14084       g_object_unref (tree_view->priv->search_entry);
14085     }
14086   else if (tree_view->priv->search_window)
14087     {
14088       gtk_widget_destroy (tree_view->priv->search_window);
14089
14090       tree_view->priv->search_window = NULL;
14091     }
14092
14093   if (entry)
14094     {
14095       tree_view->priv->search_entry = g_object_ref (entry);
14096       tree_view->priv->search_custom_entry_set = TRUE;
14097
14098       if (tree_view->priv->search_entry_changed_id == 0)
14099         {
14100           tree_view->priv->search_entry_changed_id =
14101             g_signal_connect (tree_view->priv->search_entry, "changed",
14102                               G_CALLBACK (gtk_tree_view_search_init),
14103                               tree_view);
14104         }
14105       
14106         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14107                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14108                           tree_view);
14109
14110         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14111     }
14112   else
14113     {
14114       tree_view->priv->search_entry = NULL;
14115       tree_view->priv->search_custom_entry_set = FALSE;
14116     }
14117 }
14118
14119 /**
14120  * gtk_tree_view_set_search_position_func:
14121  * @tree_view: A #GtkTreeView
14122  * @func: the function to use to position the search dialog, or %NULL
14123  *    to use the default search position function
14124  * @data: user data to pass to @func, or %NULL
14125  * @destroy: Destroy notifier for @data, or %NULL
14126  *
14127  * Sets the function to use when positioning the search dialog.
14128  *
14129  * Since: 2.10
14130  **/
14131 void
14132 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14133                                         GtkTreeViewSearchPositionFunc  func,
14134                                         gpointer                       user_data,
14135                                         GDestroyNotify                 destroy)
14136 {
14137   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14138
14139   if (tree_view->priv->search_position_destroy)
14140     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14141
14142   tree_view->priv->search_position_func = func;
14143   tree_view->priv->search_position_user_data = user_data;
14144   tree_view->priv->search_position_destroy = destroy;
14145   if (tree_view->priv->search_position_func == NULL)
14146     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14147 }
14148
14149 /**
14150  * gtk_tree_view_get_search_position_func:
14151  * @tree_view: A #GtkTreeView
14152  *
14153  * Returns the positioning function currently in use.
14154  *
14155  * Return value: the currently used function for positioning the search dialog.
14156  *
14157  * Since: 2.10
14158  */
14159 GtkTreeViewSearchPositionFunc
14160 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14161 {
14162   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14163
14164   return tree_view->priv->search_position_func;
14165 }
14166
14167
14168 static void
14169 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14170                                   GtkTreeView *tree_view)
14171 {
14172   if (tree_view->priv->disable_popdown)
14173     return;
14174
14175   if (tree_view->priv->search_entry_changed_id)
14176     {
14177       g_signal_handler_disconnect (tree_view->priv->search_entry,
14178                                    tree_view->priv->search_entry_changed_id);
14179       tree_view->priv->search_entry_changed_id = 0;
14180     }
14181   if (tree_view->priv->typeselect_flush_timeout)
14182     {
14183       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14184       tree_view->priv->typeselect_flush_timeout = 0;
14185     }
14186         
14187   if (GTK_WIDGET_VISIBLE (search_dialog))
14188     {
14189       /* send focus-in event */
14190       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14191       gtk_widget_hide (search_dialog);
14192       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14193       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14194     }
14195 }
14196
14197 static void
14198 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14199                                     GtkWidget   *search_dialog,
14200                                     gpointer     user_data)
14201 {
14202   gint x, y;
14203   gint tree_x, tree_y;
14204   gint tree_width, tree_height;
14205   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14206   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14207   GtkRequisition requisition;
14208   gint monitor_num;
14209   GdkRectangle monitor;
14210
14211   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14212   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14213
14214   gtk_widget_realize (search_dialog);
14215
14216   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14217   gdk_drawable_get_size (tree_window,
14218                          &tree_width,
14219                          &tree_height);
14220   gtk_widget_size_request (search_dialog, &requisition);
14221
14222   if (tree_x + tree_width > gdk_screen_get_width (screen))
14223     x = gdk_screen_get_width (screen) - requisition.width;
14224   else if (tree_x + tree_width - requisition.width < 0)
14225     x = 0;
14226   else
14227     x = tree_x + tree_width - requisition.width;
14228
14229   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14230     y = gdk_screen_get_height (screen) - requisition.height;
14231   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14232     y = 0;
14233   else
14234     y = tree_y + tree_height;
14235
14236   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14237 }
14238
14239 static void
14240 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14241                                       GtkMenu  *menu,
14242                                       gpointer  data)
14243 {
14244   GtkTreeView *tree_view = (GtkTreeView *)data;
14245
14246   tree_view->priv->disable_popdown = 1;
14247   g_signal_connect (menu, "hide",
14248                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14249 }
14250
14251 /* Because we're visible but offscreen, we just set a flag in the preedit
14252  * callback.
14253  */
14254 static void
14255 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14256                                       GtkTreeView  *tree_view)
14257 {
14258   tree_view->priv->imcontext_changed = 1;
14259   if (tree_view->priv->typeselect_flush_timeout)
14260     {
14261       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14262       tree_view->priv->typeselect_flush_timeout =
14263         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14264                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14265                        tree_view);
14266     }
14267
14268 }
14269
14270 static void
14271 gtk_tree_view_search_activate (GtkEntry    *entry,
14272                                GtkTreeView *tree_view)
14273 {
14274   GtkTreePath *path;
14275   GtkRBNode *node;
14276   GtkRBTree *tree;
14277
14278   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14279                                     tree_view);
14280
14281   /* If we have a row selected and it's the cursor row, we activate
14282    * the row XXX */
14283   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14284     {
14285       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14286       
14287       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14288       
14289       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14290         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14291       
14292       gtk_tree_path_free (path);
14293     }
14294 }
14295
14296 static gboolean
14297 gtk_tree_view_real_search_enable_popdown (gpointer data)
14298 {
14299   GtkTreeView *tree_view = (GtkTreeView *)data;
14300
14301   tree_view->priv->disable_popdown = 0;
14302
14303   return FALSE;
14304 }
14305
14306 static void
14307 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14308                                      gpointer   data)
14309 {
14310   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14311 }
14312
14313 static gboolean
14314 gtk_tree_view_search_delete_event (GtkWidget *widget,
14315                                    GdkEventAny *event,
14316                                    GtkTreeView *tree_view)
14317 {
14318   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14319
14320   gtk_tree_view_search_dialog_hide (widget, tree_view);
14321
14322   return TRUE;
14323 }
14324
14325 static gboolean
14326 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14327                                          GdkEventButton *event,
14328                                          GtkTreeView *tree_view)
14329 {
14330   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14331
14332   gtk_tree_view_search_dialog_hide (widget, tree_view);
14333
14334   if (event->window == tree_view->priv->bin_window)
14335     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14336
14337   return TRUE;
14338 }
14339
14340 static gboolean
14341 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14342                                    GdkEventScroll *event,
14343                                    GtkTreeView *tree_view)
14344 {
14345   gboolean retval = FALSE;
14346
14347   if (event->direction == GDK_SCROLL_UP)
14348     {
14349       gtk_tree_view_search_move (widget, tree_view, TRUE);
14350       retval = TRUE;
14351     }
14352   else if (event->direction == GDK_SCROLL_DOWN)
14353     {
14354       gtk_tree_view_search_move (widget, tree_view, FALSE);
14355       retval = TRUE;
14356     }
14357
14358   /* renew the flush timeout */
14359   if (retval && tree_view->priv->typeselect_flush_timeout
14360       && !tree_view->priv->search_custom_entry_set)
14361     {
14362       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14363       tree_view->priv->typeselect_flush_timeout =
14364         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14365                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14366                        tree_view);
14367     }
14368
14369   return retval;
14370 }
14371
14372 static gboolean
14373 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14374                                       GdkEventKey *event,
14375                                       GtkTreeView *tree_view)
14376 {
14377   gboolean retval = FALSE;
14378
14379   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14380   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14381
14382   /* close window and cancel the search */
14383   if (!tree_view->priv->search_custom_entry_set
14384       && (event->keyval == GDK_Escape ||
14385           event->keyval == GDK_Tab ||
14386             event->keyval == GDK_KP_Tab ||
14387             event->keyval == GDK_ISO_Left_Tab))
14388     {
14389       gtk_tree_view_search_dialog_hide (widget, tree_view);
14390       return TRUE;
14391     }
14392
14393   /* select previous matching iter */
14394   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14395     {
14396       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14397         gtk_widget_error_bell (widget);
14398
14399       retval = TRUE;
14400     }
14401
14402   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
14403       && (event->keyval == GDK_g || event->keyval == GDK_G))
14404     {
14405       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14406         gtk_widget_error_bell (widget);
14407
14408       retval = TRUE;
14409     }
14410
14411   /* select next matching iter */
14412   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14413     {
14414       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14415         gtk_widget_error_bell (widget);
14416
14417       retval = TRUE;
14418     }
14419
14420   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
14421       && (event->keyval == GDK_g || event->keyval == GDK_G))
14422     {
14423       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14424         gtk_widget_error_bell (widget);
14425
14426       retval = TRUE;
14427     }
14428
14429   /* renew the flush timeout */
14430   if (retval && tree_view->priv->typeselect_flush_timeout
14431       && !tree_view->priv->search_custom_entry_set)
14432     {
14433       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14434       tree_view->priv->typeselect_flush_timeout =
14435         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14436                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14437                        tree_view);
14438     }
14439
14440   return retval;
14441 }
14442
14443 /*  this function returns FALSE if there is a search string but
14444  *  nothing was found, and TRUE otherwise.
14445  */
14446 static gboolean
14447 gtk_tree_view_search_move (GtkWidget   *window,
14448                            GtkTreeView *tree_view,
14449                            gboolean     up)
14450 {
14451   gboolean ret;
14452   gint len;
14453   gint count = 0;
14454   const gchar *text;
14455   GtkTreeIter iter;
14456   GtkTreeModel *model;
14457   GtkTreeSelection *selection;
14458
14459   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14460
14461   g_return_val_if_fail (text != NULL, FALSE);
14462
14463   len = strlen (text);
14464
14465   if (up && tree_view->priv->selected_iter == 1)
14466     return strlen (text) < 1;
14467
14468   len = strlen (text);
14469
14470   if (len < 1)
14471     return TRUE;
14472
14473   model = gtk_tree_view_get_model (tree_view);
14474   selection = gtk_tree_view_get_selection (tree_view);
14475
14476   /* search */
14477   gtk_tree_selection_unselect_all (selection);
14478   if (!gtk_tree_model_get_iter_first (model, &iter))
14479     return TRUE;
14480
14481   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14482                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14483
14484   if (ret)
14485     {
14486       /* found */
14487       tree_view->priv->selected_iter += up?(-1):(1);
14488       return TRUE;
14489     }
14490   else
14491     {
14492       /* return to old iter */
14493       count = 0;
14494       gtk_tree_model_get_iter_first (model, &iter);
14495       gtk_tree_view_search_iter (model, selection,
14496                                  &iter, text,
14497                                  &count, tree_view->priv->selected_iter);
14498       return FALSE;
14499     }
14500 }
14501
14502 static gboolean
14503 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14504                                  gint          column,
14505                                  const gchar  *key,
14506                                  GtkTreeIter  *iter,
14507                                  gpointer      search_data)
14508 {
14509   gboolean retval = TRUE;
14510   const gchar *str;
14511   gchar *normalized_string;
14512   gchar *normalized_key;
14513   gchar *case_normalized_string = NULL;
14514   gchar *case_normalized_key = NULL;
14515   GValue value = {0,};
14516   GValue transformed = {0,};
14517
14518   gtk_tree_model_get_value (model, iter, column, &value);
14519
14520   g_value_init (&transformed, G_TYPE_STRING);
14521
14522   if (!g_value_transform (&value, &transformed))
14523     {
14524       g_value_unset (&value);
14525       return TRUE;
14526     }
14527
14528   g_value_unset (&value);
14529
14530   str = g_value_get_string (&transformed);
14531   if (!str)
14532     {
14533       g_value_unset (&transformed);
14534       return TRUE;
14535     }
14536
14537   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14538   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14539
14540   if (normalized_string && normalized_key)
14541     {
14542       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14543       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14544
14545       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14546         retval = FALSE;
14547     }
14548
14549   g_value_unset (&transformed);
14550   g_free (normalized_key);
14551   g_free (normalized_string);
14552   g_free (case_normalized_key);
14553   g_free (case_normalized_string);
14554
14555   return retval;
14556 }
14557
14558 static gboolean
14559 gtk_tree_view_search_iter (GtkTreeModel     *model,
14560                            GtkTreeSelection *selection,
14561                            GtkTreeIter      *iter,
14562                            const gchar      *text,
14563                            gint             *count,
14564                            gint              n)
14565 {
14566   GtkRBTree *tree = NULL;
14567   GtkRBNode *node = NULL;
14568   GtkTreePath *path;
14569
14570   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14571
14572   path = gtk_tree_model_get_path (model, iter);
14573   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14574
14575   do
14576     {
14577       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14578         {
14579           (*count)++;
14580           if (*count == n)
14581             {
14582               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14583                                             TRUE, 0.5, 0.0);
14584               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14585               gtk_tree_selection_select_iter (selection, iter);
14586
14587               if (path)
14588                 gtk_tree_path_free (path);
14589
14590               return TRUE;
14591             }
14592         }
14593
14594       if (node->children)
14595         {
14596           gboolean has_child;
14597           GtkTreeIter tmp;
14598
14599           tree = node->children;
14600           node = tree->root;
14601
14602           while (node->left != tree->nil)
14603             node = node->left;
14604
14605           tmp = *iter;
14606           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14607           gtk_tree_path_down (path);
14608
14609           /* sanity check */
14610           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14611         }
14612       else
14613         {
14614           gboolean done = FALSE;
14615
14616           do
14617             {
14618               node = _gtk_rbtree_next (tree, node);
14619
14620               if (node)
14621                 {
14622                   gboolean has_next;
14623
14624                   has_next = gtk_tree_model_iter_next (model, iter);
14625
14626                   done = TRUE;
14627                   gtk_tree_path_next (path);
14628
14629                   /* sanity check */
14630                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14631                 }
14632               else
14633                 {
14634                   gboolean has_parent;
14635                   GtkTreeIter tmp_iter = *iter;
14636
14637                   node = tree->parent_node;
14638                   tree = tree->parent_tree;
14639
14640                   if (!tree)
14641                     {
14642                       if (path)
14643                         gtk_tree_path_free (path);
14644
14645                       /* we've run out of tree, done with this func */
14646                       return FALSE;
14647                     }
14648
14649                   has_parent = gtk_tree_model_iter_parent (model,
14650                                                            iter,
14651                                                            &tmp_iter);
14652                   gtk_tree_path_up (path);
14653
14654                   /* sanity check */
14655                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14656                 }
14657             }
14658           while (!done);
14659         }
14660     }
14661   while (1);
14662
14663   return FALSE;
14664 }
14665
14666 static void
14667 gtk_tree_view_search_init (GtkWidget   *entry,
14668                            GtkTreeView *tree_view)
14669 {
14670   gint ret;
14671   gint len;
14672   gint count = 0;
14673   const gchar *text;
14674   GtkTreeIter iter;
14675   GtkTreeModel *model;
14676   GtkTreeSelection *selection;
14677
14678   g_return_if_fail (GTK_IS_ENTRY (entry));
14679   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14680
14681   text = gtk_entry_get_text (GTK_ENTRY (entry));
14682   len = strlen (text);
14683   model = gtk_tree_view_get_model (tree_view);
14684   selection = gtk_tree_view_get_selection (tree_view);
14685
14686   /* search */
14687   gtk_tree_selection_unselect_all (selection);
14688   if (tree_view->priv->typeselect_flush_timeout
14689       && !tree_view->priv->search_custom_entry_set)
14690     {
14691       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14692       tree_view->priv->typeselect_flush_timeout =
14693         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14694                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14695                        tree_view);
14696     }
14697
14698   if (len < 1)
14699     return;
14700
14701   if (!gtk_tree_model_get_iter_first (model, &iter))
14702     return;
14703
14704   ret = gtk_tree_view_search_iter (model, selection,
14705                                    &iter, text,
14706                                    &count, 1);
14707
14708   if (ret)
14709     tree_view->priv->selected_iter = 1;
14710 }
14711
14712 static void
14713 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14714                              GtkTreeView     *tree_view)
14715 {
14716   if (tree_view->priv->edited_column == NULL)
14717     return;
14718
14719   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14720   tree_view->priv->edited_column = NULL;
14721
14722   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14723     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14724
14725   g_signal_handlers_disconnect_by_func (cell_editable,
14726                                         gtk_tree_view_remove_widget,
14727                                         tree_view);
14728
14729   gtk_container_remove (GTK_CONTAINER (tree_view),
14730                         GTK_WIDGET (cell_editable));  
14731
14732   /* FIXME should only redraw a single node */
14733   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14734 }
14735
14736 static gboolean
14737 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14738                              GtkTreePath *cursor_path)
14739 {
14740   GtkTreeIter iter;
14741   GdkRectangle background_area;
14742   GdkRectangle cell_area;
14743   GtkCellEditable *editable_widget = NULL;
14744   gchar *path_string;
14745   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14746   gint retval = FALSE;
14747   GtkRBTree *cursor_tree;
14748   GtkRBNode *cursor_node;
14749
14750   g_assert (tree_view->priv->focus_column);
14751
14752   if (! GTK_WIDGET_REALIZED (tree_view))
14753     return FALSE;
14754
14755   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14756       cursor_node == NULL)
14757     return FALSE;
14758
14759   path_string = gtk_tree_path_to_string (cursor_path);
14760   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14761
14762   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14763
14764   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14765                                            tree_view->priv->model,
14766                                            &iter,
14767                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14768                                            cursor_node->children?TRUE:FALSE);
14769   gtk_tree_view_get_background_area (tree_view,
14770                                      cursor_path,
14771                                      tree_view->priv->focus_column,
14772                                      &background_area);
14773   gtk_tree_view_get_cell_area (tree_view,
14774                                cursor_path,
14775                                tree_view->priv->focus_column,
14776                                &cell_area);
14777
14778   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14779                                         &editable_widget,
14780                                         NULL,
14781                                         path_string,
14782                                         &background_area,
14783                                         &cell_area,
14784                                         flags))
14785     {
14786       retval = TRUE;
14787       if (editable_widget != NULL)
14788         {
14789           gint left, right;
14790           GdkRectangle area;
14791           GtkCellRenderer *cell;
14792
14793           area = cell_area;
14794           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14795
14796           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14797
14798           area.x += left;
14799           area.width -= right + left;
14800
14801           gtk_tree_view_real_start_editing (tree_view,
14802                                             tree_view->priv->focus_column,
14803                                             cursor_path,
14804                                             editable_widget,
14805                                             &area,
14806                                             NULL,
14807                                             flags);
14808         }
14809
14810     }
14811   g_free (path_string);
14812   return retval;
14813 }
14814
14815 static void
14816 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14817                                   GtkTreeViewColumn *column,
14818                                   GtkTreePath       *path,
14819                                   GtkCellEditable   *cell_editable,
14820                                   GdkRectangle      *cell_area,
14821                                   GdkEvent          *event,
14822                                   guint              flags)
14823 {
14824   gint pre_val = tree_view->priv->vadjustment->value;
14825   GtkRequisition requisition;
14826
14827   tree_view->priv->edited_column = column;
14828   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14829
14830   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14831   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14832
14833   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14834
14835   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14836
14837   if (requisition.height < cell_area->height)
14838     {
14839       gint diff = cell_area->height - requisition.height;
14840       gtk_tree_view_put (tree_view,
14841                          GTK_WIDGET (cell_editable),
14842                          cell_area->x, cell_area->y + diff/2,
14843                          cell_area->width, requisition.height);
14844     }
14845   else
14846     {
14847       gtk_tree_view_put (tree_view,
14848                          GTK_WIDGET (cell_editable),
14849                          cell_area->x, cell_area->y,
14850                          cell_area->width, cell_area->height);
14851     }
14852
14853   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14854                                    (GdkEvent *)event);
14855
14856   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14857   g_signal_connect (cell_editable, "remove-widget",
14858                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14859 }
14860
14861 static void
14862 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14863                             gboolean     cancel_editing)
14864 {
14865   GtkTreeViewColumn *column;
14866   GtkCellRenderer *cell;
14867
14868   if (tree_view->priv->edited_column == NULL)
14869     return;
14870
14871   /*
14872    * This is very evil. We need to do this, because
14873    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14874    * later on. If gtk_tree_view_row_changed notices
14875    * tree_view->priv->edited_column != NULL, it'll call
14876    * gtk_tree_view_stop_editing again. Bad things will happen then.
14877    *
14878    * Please read that again if you intend to modify anything here.
14879    */
14880
14881   column = tree_view->priv->edited_column;
14882   tree_view->priv->edited_column = NULL;
14883
14884   cell = _gtk_tree_view_column_get_edited_cell (column);
14885   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14886
14887   if (!cancel_editing)
14888     gtk_cell_editable_editing_done (column->editable_widget);
14889
14890   tree_view->priv->edited_column = column;
14891
14892   gtk_cell_editable_remove_widget (column->editable_widget);
14893 }
14894
14895
14896 /**
14897  * gtk_tree_view_set_hover_selection:
14898  * @tree_view: a #GtkTreeView
14899  * @hover: %TRUE to enable hover selection mode
14900  *
14901  * Enables of disables the hover selection mode of @tree_view.
14902  * Hover selection makes the selected row follow the pointer.
14903  * Currently, this works only for the selection modes 
14904  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14905  * 
14906  * Since: 2.6
14907  **/
14908 void     
14909 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14910                                    gboolean     hover)
14911 {
14912   hover = hover != FALSE;
14913
14914   if (hover != tree_view->priv->hover_selection)
14915     {
14916       tree_view->priv->hover_selection = hover;
14917
14918       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14919     }
14920 }
14921
14922 /**
14923  * gtk_tree_view_get_hover_selection:
14924  * @tree_view: a #GtkTreeView
14925  * 
14926  * Returns whether hover selection mode is turned on for @tree_view.
14927  * 
14928  * Return value: %TRUE if @tree_view is in hover selection mode
14929  *
14930  * Since: 2.6 
14931  **/
14932 gboolean 
14933 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14934 {
14935   return tree_view->priv->hover_selection;
14936 }
14937
14938 /**
14939  * gtk_tree_view_set_hover_expand:
14940  * @tree_view: a #GtkTreeView
14941  * @expand: %TRUE to enable hover selection mode
14942  *
14943  * Enables of disables the hover expansion mode of @tree_view.
14944  * Hover expansion makes rows expand or collapse if the pointer 
14945  * moves over them.
14946  * 
14947  * Since: 2.6
14948  **/
14949 void     
14950 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14951                                 gboolean     expand)
14952 {
14953   expand = expand != FALSE;
14954
14955   if (expand != tree_view->priv->hover_expand)
14956     {
14957       tree_view->priv->hover_expand = expand;
14958
14959       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14960     }
14961 }
14962
14963 /**
14964  * gtk_tree_view_get_hover_expand:
14965  * @tree_view: a #GtkTreeView
14966  * 
14967  * Returns whether hover expansion mode is turned on for @tree_view.
14968  * 
14969  * Return value: %TRUE if @tree_view is in hover expansion mode
14970  *
14971  * Since: 2.6 
14972  **/
14973 gboolean 
14974 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14975 {
14976   return tree_view->priv->hover_expand;
14977 }
14978
14979 /**
14980  * gtk_tree_view_set_rubber_banding:
14981  * @tree_view: a #GtkTreeView
14982  * @enable: %TRUE to enable rubber banding
14983  *
14984  * Enables or disables rubber banding in @tree_view.  If the selection mode
14985  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14986  * multiple rows by dragging the mouse.
14987  * 
14988  * Since: 2.10
14989  **/
14990 void
14991 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14992                                   gboolean     enable)
14993 {
14994   enable = enable != FALSE;
14995
14996   if (enable != tree_view->priv->rubber_banding_enable)
14997     {
14998       tree_view->priv->rubber_banding_enable = enable;
14999
15000       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15001     }
15002 }
15003
15004 /**
15005  * gtk_tree_view_get_rubber_banding:
15006  * @tree_view: a #GtkTreeView
15007  * 
15008  * Returns whether rubber banding is turned on for @tree_view.  If the
15009  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15010  * user to select multiple rows by dragging the mouse.
15011  * 
15012  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15013  *
15014  * Since: 2.10
15015  **/
15016 gboolean
15017 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15018 {
15019   return tree_view->priv->rubber_banding_enable;
15020 }
15021
15022 /**
15023  * gtk_tree_view_is_rubber_banding_active:
15024  * @tree_view: a #GtkTreeView
15025  * 
15026  * Returns whether a rubber banding operation is currently being done
15027  * in @tree_view.
15028  *
15029  * Return value: %TRUE if a rubber banding operation is currently being
15030  * done in @tree_view.
15031  *
15032  * Since: 2.12
15033  **/
15034 gboolean
15035 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15036 {
15037   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15038
15039   if (tree_view->priv->rubber_banding_enable
15040       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15041     return TRUE;
15042
15043   return FALSE;
15044 }
15045
15046 /**
15047  * gtk_tree_view_get_row_separator_func:
15048  * @tree_view: a #GtkTreeView
15049  * 
15050  * Returns the current row separator function.
15051  * 
15052  * Return value: the current row separator function.
15053  *
15054  * Since: 2.6
15055  **/
15056 GtkTreeViewRowSeparatorFunc 
15057 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15058 {
15059   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15060
15061   return tree_view->priv->row_separator_func;
15062 }
15063
15064 /**
15065  * gtk_tree_view_set_row_separator_func:
15066  * @tree_view: a #GtkTreeView
15067  * @func: a #GtkTreeViewRowSeparatorFunc
15068  * @data: user data to pass to @func, or %NULL
15069  * @destroy: destroy notifier for @data, or %NULL
15070  * 
15071  * Sets the row separator function, which is used to determine
15072  * whether a row should be drawn as a separator. If the row separator
15073  * function is %NULL, no separators are drawn. This is the default value.
15074  *
15075  * Since: 2.6
15076  **/
15077 void
15078 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15079                                       GtkTreeViewRowSeparatorFunc  func,
15080                                       gpointer                     data,
15081                                       GDestroyNotify               destroy)
15082 {
15083   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15084
15085   if (tree_view->priv->row_separator_destroy)
15086     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15087
15088   tree_view->priv->row_separator_func = func;
15089   tree_view->priv->row_separator_data = data;
15090   tree_view->priv->row_separator_destroy = destroy;
15091 }
15092
15093   
15094 static void
15095 gtk_tree_view_grab_notify (GtkWidget *widget,
15096                            gboolean   was_grabbed)
15097 {
15098   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15099
15100   tree_view->priv->in_grab = !was_grabbed;
15101
15102   if (!was_grabbed)
15103     {
15104       tree_view->priv->pressed_button = -1;
15105
15106       if (tree_view->priv->rubber_band_status)
15107         gtk_tree_view_stop_rubber_band (tree_view);
15108     }
15109 }
15110
15111 static void
15112 gtk_tree_view_state_changed (GtkWidget      *widget,
15113                              GtkStateType    previous_state)
15114 {
15115   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15116
15117   if (GTK_WIDGET_REALIZED (widget))
15118     {
15119       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15120       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15121     }
15122
15123   gtk_widget_queue_draw (widget);
15124 }
15125
15126 /**
15127  * gtk_tree_view_get_grid_lines:
15128  * @tree_view: a #GtkTreeView
15129  *
15130  * Returns which grid lines are enabled in @tree_view.
15131  *
15132  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15133  * are enabled.
15134  *
15135  * Since: 2.10
15136  */
15137 GtkTreeViewGridLines
15138 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15139 {
15140   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15141
15142   return tree_view->priv->grid_lines;
15143 }
15144
15145 /**
15146  * gtk_tree_view_set_grid_lines:
15147  * @tree_view: a #GtkTreeView
15148  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15149  * enable.
15150  *
15151  * Sets which grid lines to draw in @tree_view.
15152  *
15153  * Since: 2.10
15154  */
15155 void
15156 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15157                               GtkTreeViewGridLines   grid_lines)
15158 {
15159   GtkTreeViewPrivate *priv;
15160   GtkWidget *widget;
15161   GtkTreeViewGridLines old_grid_lines;
15162
15163   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15164
15165   priv = tree_view->priv;
15166   widget = GTK_WIDGET (tree_view);
15167
15168   old_grid_lines = priv->grid_lines;
15169   priv->grid_lines = grid_lines;
15170   
15171   if (GTK_WIDGET_REALIZED (widget))
15172     {
15173       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15174           priv->grid_line_gc)
15175         {
15176           g_object_unref (priv->grid_line_gc);
15177           priv->grid_line_gc = NULL;
15178         }
15179       
15180       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15181           !priv->grid_line_gc)
15182         {
15183           gint line_width;
15184           gint8 *dash_list;
15185
15186           gtk_widget_style_get (widget,
15187                                 "grid-line-width", &line_width,
15188                                 "grid-line-pattern", (gchar *)&dash_list,
15189                                 NULL);
15190       
15191           priv->grid_line_gc = gdk_gc_new (widget->window);
15192           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15193           
15194           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15195                                       GDK_LINE_ON_OFF_DASH,
15196                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15197           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15198
15199           g_free (dash_list);
15200         }      
15201     }
15202
15203   if (old_grid_lines != grid_lines)
15204     {
15205       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15206       
15207       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15208     }
15209 }
15210
15211 /**
15212  * gtk_tree_view_get_enable_tree_lines:
15213  * @tree_view: a #GtkTreeView.
15214  *
15215  * Returns whether or not tree lines are drawn in @tree_view.
15216  *
15217  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15218  * otherwise.
15219  *
15220  * Since: 2.10
15221  */
15222 gboolean
15223 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15224 {
15225   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15226
15227   return tree_view->priv->tree_lines_enabled;
15228 }
15229
15230 /**
15231  * gtk_tree_view_set_enable_tree_lines:
15232  * @tree_view: a #GtkTreeView
15233  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15234  *
15235  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15236  * This does not have any visible effects for lists.
15237  *
15238  * Since: 2.10
15239  */
15240 void
15241 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15242                                      gboolean     enabled)
15243 {
15244   GtkTreeViewPrivate *priv;
15245   GtkWidget *widget;
15246   gboolean was_enabled;
15247
15248   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15249
15250   enabled = enabled != FALSE;
15251
15252   priv = tree_view->priv;
15253   widget = GTK_WIDGET (tree_view);
15254
15255   was_enabled = priv->tree_lines_enabled;
15256
15257   priv->tree_lines_enabled = enabled;
15258
15259   if (GTK_WIDGET_REALIZED (widget))
15260     {
15261       if (!enabled && priv->tree_line_gc)
15262         {
15263           g_object_unref (priv->tree_line_gc);
15264           priv->tree_line_gc = NULL;
15265         }
15266       
15267       if (enabled && !priv->tree_line_gc)
15268         {
15269           gint line_width;
15270           gint8 *dash_list;
15271           gtk_widget_style_get (widget,
15272                                 "tree-line-width", &line_width,
15273                                 "tree-line-pattern", (gchar *)&dash_list,
15274                                 NULL);
15275           
15276           priv->tree_line_gc = gdk_gc_new (widget->window);
15277           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15278           
15279           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15280                                       GDK_LINE_ON_OFF_DASH,
15281                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15282           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15283
15284           g_free (dash_list);
15285         }
15286     }
15287
15288   if (was_enabled != enabled)
15289     {
15290       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15291
15292       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15293     }
15294 }
15295
15296
15297 /**
15298  * gtk_tree_view_set_show_expanders:
15299  * @tree_view: a #GtkTreeView
15300  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15301  *
15302  * Sets whether to draw and enable expanders and indent child rows in
15303  * @tree_view.  When disabled there will be no expanders visible in trees
15304  * and there will be no way to expand and collapse rows by default.  Also
15305  * note that hiding the expanders will disable the default indentation.  You
15306  * can set a custom indentation in this case using
15307  * gtk_tree_view_set_level_indentation().
15308  * This does not have any visible effects for lists.
15309  *
15310  * Since: 2.12
15311  */
15312 void
15313 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15314                                   gboolean     enabled)
15315 {
15316   gboolean was_enabled;
15317
15318   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15319
15320   enabled = enabled != FALSE;
15321   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15322
15323   if (enabled)
15324     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15325   else
15326     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15327
15328   if (enabled != was_enabled)
15329     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15330 }
15331
15332 /**
15333  * gtk_tree_view_get_show_expanders:
15334  * @tree_view: a #GtkTreeView.
15335  *
15336  * Returns whether or not expanders are drawn in @tree_view.
15337  *
15338  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15339  * otherwise.
15340  *
15341  * Since: 2.12
15342  */
15343 gboolean
15344 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15345 {
15346   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15347
15348   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15349 }
15350
15351 /**
15352  * gtk_tree_view_set_level_indentation:
15353  * @tree_view: a #GtkTreeView
15354  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15355  *
15356  * Sets the amount of extra indentation for child levels to use in @tree_view
15357  * in addition to the default indentation.  The value should be specified in
15358  * pixels, a value of 0 disables this feature and in this case only the default
15359  * indentation will be used.
15360  * This does not have any visible effects for lists.
15361  *
15362  * Since: 2.12
15363  */
15364 void
15365 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15366                                      gint         indentation)
15367 {
15368   tree_view->priv->level_indentation = indentation;
15369
15370   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15371 }
15372
15373 /**
15374  * gtk_tree_view_get_level_indentation:
15375  * @tree_view: a #GtkTreeView.
15376  *
15377  * Returns the amount, in pixels, of extra indentation for child levels
15378  * in @tree_view.
15379  *
15380  * Return value: the amount of extra indentation for child levels in
15381  * @tree_view.  A return value of 0 means that this feature is disabled.
15382  *
15383  * Since: 2.12
15384  */
15385 gint
15386 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15387 {
15388   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15389
15390   return tree_view->priv->level_indentation;
15391 }
15392
15393 /**
15394  * gtk_tree_view_set_tooltip_row:
15395  * @tree_view: a #GtkTreeView
15396  * @tooltip: a #GtkTooltip
15397  * @path: a #GtkTreePath
15398  *
15399  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15400  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15401  * See also gtk_tooltip_set_tip_area().
15402  *
15403  * Since: 2.12
15404  */
15405 void
15406 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15407                                GtkTooltip  *tooltip,
15408                                GtkTreePath *path)
15409 {
15410   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15411   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15412
15413   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15414 }
15415
15416 /**
15417  * gtk_tree_view_set_tooltip_cell:
15418  * @tree_view: a #GtkTreeView
15419  * @tooltip: a #GtkTooltip
15420  * @path: a #GtkTreePath or %NULL
15421  * @column: a #GtkTreeViewColumn or %NULL
15422  * @cell: a #GtkCellRenderer or %NULL
15423  *
15424  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15425  * in common.  For example if @path is %NULL and @column is set, the tip
15426  * area will be set to the full area covered by @column.  See also
15427  * gtk_tooltip_set_tip_area().
15428  *
15429  * Note that if @path is not specified and @cell is set and part of a column
15430  * containing the expander, the tooltip might not show and hide at the correct
15431  * position.  In such cases @path must be set to the current node under the
15432  * mouse cursor for this function to operate correctly.
15433  *
15434  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15435  *
15436  * Since: 2.12
15437  */
15438 void
15439 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15440                                 GtkTooltip        *tooltip,
15441                                 GtkTreePath       *path,
15442                                 GtkTreeViewColumn *column,
15443                                 GtkCellRenderer   *cell)
15444 {
15445   GdkRectangle rect;
15446
15447   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15448   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15449
15450   if (column)
15451     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
15452
15453   if (cell)
15454     g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
15455
15456   /* Determine x values. */
15457   if (column && cell)
15458     {
15459       GdkRectangle tmp;
15460       gint start, width;
15461
15462       /* We always pass in path here, whether it is NULL or not.
15463        * For cells in expander columns path must be specified so that
15464        * we can correctly account for the indentation.  This also means
15465        * that the tooltip is constrained vertically by the "Determine y
15466        * values" code below; this is not a real problem since cells actually
15467        * don't stretch vertically in constrast to columns.
15468        */
15469       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15470       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15471
15472       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15473                                                          tmp.x + start, 0,
15474                                                          &rect.x, NULL);
15475       rect.width = width;
15476     }
15477   else if (column)
15478     {
15479       GdkRectangle tmp;
15480
15481       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15482       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15483                                                          tmp.x, 0,
15484                                                          &rect.x, NULL);
15485       rect.width = tmp.width;
15486     }
15487   else
15488     {
15489       rect.x = 0;
15490       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15491     }
15492
15493   /* Determine y values. */
15494   if (path)
15495     {
15496       GdkRectangle tmp;
15497
15498       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15499       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15500                                                          0, tmp.y,
15501                                                          NULL, &rect.y);
15502       rect.height = tmp.height;
15503     }
15504   else
15505     {
15506       rect.y = 0;
15507       rect.height = tree_view->priv->vadjustment->page_size;
15508     }
15509
15510   gtk_tooltip_set_tip_area (tooltip, &rect);
15511 }
15512
15513 /**
15514  * gtk_tree_view_get_tooltip_context:
15515  * @tree_view: a #GtkTreeView
15516  * @x: the x coordinate (relative to widget coordinates)
15517  * @y: the y coordinate (relative to widget coordinates)
15518  * @keyboard_tip: whether this is a keyboard tooltip or not
15519  * @model: a pointer to receive a #GtkTreeModel or %NULL
15520  * @path: a pointer to receive a #GtkTreePath or %NULL
15521  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15522  *
15523  * This function is supposed to be used in a #GtkWidget::query-tooltip
15524  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15525  * which are received in the signal handler, should be passed to this
15526  * function without modification.
15527  *
15528  * The return value indicates whether there is a tree view row at the given
15529  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15530  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15531  * @model, @path and @iter which have been provided will be set to point to
15532  * that row and the corresponding model.  @x and @y will always be converted
15533  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15534  *
15535  * Return value: whether or not the given tooltip context points to a row.
15536  *
15537  * Since: 2.12
15538  */
15539 gboolean
15540 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15541                                    gint          *x,
15542                                    gint          *y,
15543                                    gboolean       keyboard_tip,
15544                                    GtkTreeModel **model,
15545                                    GtkTreePath  **path,
15546                                    GtkTreeIter   *iter)
15547 {
15548   GtkTreePath *tmppath = NULL;
15549
15550   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15551   g_return_val_if_fail (x != NULL, FALSE);
15552   g_return_val_if_fail (y != NULL, FALSE);
15553
15554   if (keyboard_tip)
15555     {
15556       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15557
15558       if (!tmppath)
15559         return FALSE;
15560     }
15561   else
15562     {
15563       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15564                                                          x, y);
15565
15566       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15567                                           &tmppath, NULL, NULL, NULL))
15568         return FALSE;
15569     }
15570
15571   if (model)
15572     *model = gtk_tree_view_get_model (tree_view);
15573
15574   if (iter)
15575     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15576                              iter, tmppath);
15577
15578   if (path)
15579     *path = tmppath;
15580   else
15581     gtk_tree_path_free (tmppath);
15582
15583   return TRUE;
15584 }
15585
15586 static gboolean
15587 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15588                                     gint        x,
15589                                     gint        y,
15590                                     gboolean    keyboard_tip,
15591                                     GtkTooltip *tooltip,
15592                                     gpointer    data)
15593 {
15594   GValue value = { 0, };
15595   GValue transformed = { 0, };
15596   GtkTreeIter iter;
15597   GtkTreePath *path;
15598   GtkTreeModel *model;
15599   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15600
15601   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15602                                           &x, &y,
15603                                           keyboard_tip,
15604                                           &model, &path, &iter))
15605     return FALSE;
15606
15607   gtk_tree_model_get_value (model, &iter,
15608                             tree_view->priv->tooltip_column, &value);
15609
15610   g_value_init (&transformed, G_TYPE_STRING);
15611
15612   if (!g_value_transform (&value, &transformed))
15613     {
15614       g_value_unset (&value);
15615       gtk_tree_path_free (path);
15616
15617       return FALSE;
15618     }
15619
15620   g_value_unset (&value);
15621
15622   if (!g_value_get_string (&transformed))
15623     {
15624       g_value_unset (&transformed);
15625       gtk_tree_path_free (path);
15626
15627       return FALSE;
15628     }
15629
15630   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15631   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15632
15633   gtk_tree_path_free (path);
15634   g_value_unset (&transformed);
15635
15636   return TRUE;
15637 }
15638
15639 /**
15640  * gtk_tree_view_set_tooltip_column:
15641  * @tree_view: a #GtkTreeView
15642  * @column: an integer, which is a valid column number for @tree_view's model
15643  *
15644  * If you only plan to have simple (text-only) tooltips on full rows, you
15645  * can use this function to have #GtkTreeView handle these automatically
15646  * for you. @column should be set to the column in @tree_view's model
15647  * containing the tooltip texts, or -1 to disable this feature.
15648  *
15649  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15650  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15651  *
15652  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15653  * so &amp;, &lt;, etc have to be escaped in the text.
15654  *
15655  * Since: 2.12
15656  */
15657 void
15658 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15659                                   gint         column)
15660 {
15661   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15662
15663   if (column == tree_view->priv->tooltip_column)
15664     return;
15665
15666   if (column == -1)
15667     {
15668       g_signal_handlers_disconnect_by_func (tree_view,
15669                                             gtk_tree_view_set_tooltip_query_cb,
15670                                             NULL);
15671       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15672     }
15673   else
15674     {
15675       if (tree_view->priv->tooltip_column == -1)
15676         {
15677           g_signal_connect (tree_view, "query-tooltip",
15678                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15679           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15680         }
15681     }
15682
15683   tree_view->priv->tooltip_column = column;
15684   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15685 }
15686
15687 /**
15688  * gtk_tree_view_get_tooltip_column:
15689  * @tree_view: a #GtkTreeView
15690  *
15691  * Returns the column of @tree_view's model which is being used for
15692  * displaying tooltips on @tree_view's rows.
15693  *
15694  * Return value: the index of the tooltip column that is currently being
15695  * used, or -1 if this is disabled.
15696  *
15697  * Since: 2.12
15698  */
15699 gint
15700 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15701 {
15702   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15703
15704   return tree_view->priv->tooltip_column;
15705 }
15706
15707 #define __GTK_TREE_VIEW_C__
15708 #include "gtkaliasdef.c"